Compare commits
613 Commits
V_0_8_1
...
benzea/ci-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1528c962fa | ||
|
|
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 |
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!')
|
||||||
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
|
|
||||||
|
|||||||
148
.gitlab-ci.yml
@@ -1,20 +1,146 @@
|
|||||||
image: fedora:rawhide
|
include:
|
||||||
stages:
|
- local: '.gitlab-ci/libfprint-templates.yaml'
|
||||||
- build
|
- project: 'wayland/ci-templates'
|
||||||
|
ref: master
|
||||||
|
file: '/templates/fedora.yml'
|
||||||
|
|
||||||
variables:
|
variables:
|
||||||
DEPENDENCIES: libusb1-devel glib2-devel nss-devel pixman-devel systemd meson gtk-doc
|
extends: .libfprint_common_variables
|
||||||
gcc gcc-c++ glibc-devel libX11-devel libXv-devel
|
FDO_DISTRIBUTION_TAG: latest
|
||||||
|
FDO_DISTRIBUTION_VERSION: rawhide
|
||||||
|
FEDORA_IMAGE: "$CI_REGISTRY/libfprint/$CI_PROJECT_NAME/fedora/$FDO_DISTRIBUTION_VERSION:$FDO_DISTRIBUTION_TAG"
|
||||||
|
BUNDLE: "org.freedesktop.libfprint.Demo.flatpak"
|
||||||
|
LAST_ABI_BREAK: "056ea541ddc97f5806cffbd99a12dc87e4da3546"
|
||||||
|
|
||||||
|
stages:
|
||||||
|
- check-source
|
||||||
|
- build
|
||||||
|
- test
|
||||||
|
- flatpak
|
||||||
|
|
||||||
before_script:
|
image: "$FEDORA_IMAGE"
|
||||||
- dnf update -y --nogpgcheck && dnf install -y --nogpgcheck $DEPENDENCIES
|
|
||||||
|
|
||||||
|
.build_one_driver_template: &build_one_driver
|
||||||
build:
|
|
||||||
stage: build
|
|
||||||
script:
|
script:
|
||||||
- meson . _build
|
# Build with a driver that doesn't need imaging, or nss
|
||||||
|
- meson --werror -Ddrivers=$driver . _build
|
||||||
|
- ninja -C _build
|
||||||
|
- rm -rf _build/
|
||||||
|
|
||||||
|
.build_template: &build
|
||||||
|
script:
|
||||||
|
# And build with everything
|
||||||
|
- meson --werror -Ddrivers=all . _build
|
||||||
- ninja -C _build
|
- ninja -C _build
|
||||||
- ninja -C _build install
|
- ninja -C _build install
|
||||||
|
|
||||||
|
.build_template: &check_abi
|
||||||
|
script:
|
||||||
|
- ./.ci/check-abi ${LAST_ABI_BREAK} $(git rev-parse HEAD)
|
||||||
|
|
||||||
|
build:
|
||||||
|
stage: build
|
||||||
|
except:
|
||||||
|
variables:
|
||||||
|
- $CI_PIPELINE_SOURCE == "schedule"
|
||||||
|
variables:
|
||||||
|
driver: virtual_image
|
||||||
|
<<: *build_one_driver
|
||||||
|
<<: *build
|
||||||
|
# <<: *check_abi
|
||||||
|
|
||||||
|
test:
|
||||||
|
stage: test
|
||||||
|
except:
|
||||||
|
variables:
|
||||||
|
- $CI_PIPELINE_SOURCE == "schedule"
|
||||||
|
script:
|
||||||
|
- meson --werror -Ddrivers=all -Db_coverage=true . _build
|
||||||
|
- ninja -C _build
|
||||||
|
- meson test -C _build --verbose --no-stdsplit
|
||||||
|
- ninja -C _build coverage
|
||||||
|
- cat _build/meson-logs/coverage.txt
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- _build/meson-logs
|
||||||
|
expire_in: 1 week
|
||||||
|
|
||||||
|
test_valgrind:
|
||||||
|
stage: test
|
||||||
|
except:
|
||||||
|
variables:
|
||||||
|
- $CI_PIPELINE_SOURCE == "schedule"
|
||||||
|
script:
|
||||||
|
- meson -Ddrivers=all . _build
|
||||||
|
- ninja -C _build
|
||||||
|
- meson test -C _build --verbose --no-stdsplit --setup=valgrind
|
||||||
|
|
||||||
|
test_indent:
|
||||||
|
stage: check-source
|
||||||
|
except:
|
||||||
|
variables:
|
||||||
|
- $CI_PIPELINE_SOURCE == "schedule"
|
||||||
|
script:
|
||||||
|
- scripts/uncrustify.sh --check
|
||||||
|
|
||||||
|
.flatpak_script_template: &flatpak_script
|
||||||
|
script:
|
||||||
|
- flatpak-builder --stop-at=${FLATPAK_MODULE} app ${MANIFEST_PATH}
|
||||||
|
# Make sure to keep this in sync with the Flatpak manifest, all arguments
|
||||||
|
# are passed except the config-args because we build it ourselves
|
||||||
|
- flatpak build app meson --prefix=/app --libdir=lib ${MESON_ARGS} _build
|
||||||
|
- flatpak build app ninja -C _build install
|
||||||
|
- flatpak build app rm -rf /app/include/ /app/lib/pkgconfig/
|
||||||
|
- flatpak-builder --finish-only --repo=repo app ${MANIFEST_PATH}
|
||||||
|
# Generate a Flatpak bundle
|
||||||
|
- flatpak build-bundle repo ${BUNDLE} --runtime-repo=${RUNTIME_REPO} ${DBUS_ID}
|
||||||
|
|
||||||
|
.flatpak_artifacts_template: &flatpak_artifacts
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- ${BUNDLE}
|
||||||
|
when: always
|
||||||
|
expire_in: 30 days
|
||||||
|
|
||||||
|
.flatpak_template: &flatpak
|
||||||
|
<<: *flatpak_script
|
||||||
|
<<: *flatpak_artifacts
|
||||||
|
|
||||||
|
.flatpak_master_template: &flatpak_master
|
||||||
|
image: registry.gitlab.gnome.org/gnome/gnome-runtime-images/gnome:3.32
|
||||||
|
stage: flatpak
|
||||||
|
variables:
|
||||||
|
MANIFEST_PATH: "demo/org.freedesktop.libfprint.Demo.json"
|
||||||
|
# From demo/org.freedesktop.libfprint.Demo.json
|
||||||
|
MESON_ARGS: "-Dudev_rules=false -Dx11-examples=false -Dgtk-examples=true"
|
||||||
|
FLATPAK_MODULE: "libfprint"
|
||||||
|
DBUS_ID: "org.freedesktop.libfprint.Demo"
|
||||||
|
<<: *flatpak
|
||||||
|
|
||||||
|
flatpak-auto master:
|
||||||
|
<<: *flatpak_master
|
||||||
|
when: always
|
||||||
|
only:
|
||||||
|
- tags
|
||||||
|
- master
|
||||||
|
|
||||||
|
flatpak-manual master:
|
||||||
|
<<: *flatpak_master
|
||||||
|
when: manual
|
||||||
|
except:
|
||||||
|
refs:
|
||||||
|
- tags
|
||||||
|
- master
|
||||||
|
variables:
|
||||||
|
- $CI_PIPELINE_SOURCE == "schedule"
|
||||||
|
|
||||||
|
# CONTAINERS creation stage
|
||||||
|
container_fedora_build:
|
||||||
|
extends: .fdo.container-build@fedora
|
||||||
|
only:
|
||||||
|
variables:
|
||||||
|
- $CI_PIPELINE_SOURCE == "schedule" && $CRON_TASK == "BUILD_CI_IMAGES"
|
||||||
|
variables:
|
||||||
|
GIT_STRATEGY: none # no need to pull the whole tree for rebuilding the image
|
||||||
|
# a list of packages to install
|
||||||
|
FDO_DISTRIBUTION_PACKAGES: $LIBFPRINT_DEPENDENCIES
|
||||||
|
|||||||
26
.gitlab-ci/libfprint-templates.yaml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
.libfprint_common_variables:
|
||||||
|
LIBFPRINT_DEPENDENCIES:
|
||||||
|
doxygen
|
||||||
|
flatpak-builder
|
||||||
|
gcc
|
||||||
|
gcc-c++
|
||||||
|
gcovr
|
||||||
|
git
|
||||||
|
glib2-devel
|
||||||
|
glibc-devel
|
||||||
|
gobject-introspection-devel
|
||||||
|
gtk-doc
|
||||||
|
gtk3-devel
|
||||||
|
libabigail
|
||||||
|
libgusb-devel
|
||||||
|
libX11-devel
|
||||||
|
libXv-devel
|
||||||
|
meson
|
||||||
|
nss-devel
|
||||||
|
pixman-devel
|
||||||
|
python3-cairo
|
||||||
|
python3-gobject
|
||||||
|
systemd
|
||||||
|
umockdev
|
||||||
|
uncrustify
|
||||||
|
valgrind
|
||||||
25
HACKING.md
@@ -3,8 +3,29 @@
|
|||||||
## GLib
|
## GLib
|
||||||
|
|
||||||
Although the library uses GLib internally, libfprint is designed to provide
|
Although the library uses GLib internally, libfprint is designed to provide
|
||||||
a completely neutral interface to it's application users. So, the public
|
a completely neutral interface to its application users. So, the public
|
||||||
APIs should never return GLib data types or anything like that.
|
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
|
## Two-faced-ness
|
||||||
|
|
||||||
|
|||||||
114
NEWS
@@ -1,6 +1,120 @@
|
|||||||
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.
|
||||||
|
|
||||||
|
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
|
2018-06-12: v0.8.1 release
|
||||||
- Brown paperbag release to install the udev rules file in the correct
|
- 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
|
directory if the udev pkg-config file doesn't have a trailing slash
|
||||||
|
|||||||
10
README
@@ -39,3 +39,13 @@ We include bozorth3 from the US export controlled distribution. We have
|
|||||||
determined that it is fine to ship bozorth3 in an open source project,
|
determined that it is fine to ship bozorth3 in an open source project,
|
||||||
see https://fprint.freedesktop.org/us-export-control.html
|
see https://fprint.freedesktop.org/us-export-control.html
|
||||||
|
|
||||||
|
## Historical links
|
||||||
|
|
||||||
|
Older versions of libfprint are available at:
|
||||||
|
https://sourceforge.net/projects/fprint/files/
|
||||||
|
|
||||||
|
Historical mailing-list archives:
|
||||||
|
http://www.reactivated.net/fprint_list_archives/
|
||||||
|
|
||||||
|
Historical website:
|
||||||
|
http://web.archive.org/web/*/https://www.freedesktop.org/wiki/Software/fprint/
|
||||||
|
|||||||
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/
|
||||||
565
demo/gtk-libfprint-test.c
Normal file
@@ -0,0 +1,565 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
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_supports_capture (g_ptr_array_index (devices, 0)))
|
||||||
|
{
|
||||||
|
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
|
||||||
63
demo/org.freedesktop.libfprint.Demo.json
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
{
|
||||||
|
"app-id": "org.freedesktop.libfprint.Demo",
|
||||||
|
"runtime": "org.gnome.Platform",
|
||||||
|
"runtime-version": "3.32",
|
||||||
|
"sdk": "org.gnome.Sdk",
|
||||||
|
"command": "gtk-libfprint-test",
|
||||||
|
"finish-args": [
|
||||||
|
/* X11 + XShm access */
|
||||||
|
"--share=ipc", "--socket=x11",
|
||||||
|
/* Wayland access */
|
||||||
|
"--socket=wayland",
|
||||||
|
/* OpenGL access */
|
||||||
|
"--device=dri",
|
||||||
|
/* USB access */
|
||||||
|
"--device=all"
|
||||||
|
],
|
||||||
|
"cleanup": [ "/include", "/lib/pkgconfig/" ],
|
||||||
|
"modules": [
|
||||||
|
{
|
||||||
|
"name": "libusb",
|
||||||
|
"config-opts": [ "--disable-static", "--disable-udev" ],
|
||||||
|
"cleanup": [
|
||||||
|
"/lib/*.la",
|
||||||
|
"/lib/pkgconfig",
|
||||||
|
"/include"
|
||||||
|
],
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"type": "archive",
|
||||||
|
"url": "https://github.com/libusb/libusb/archive/v1.0.22.tar.gz",
|
||||||
|
"sha256": "3500f7b182750cd9ccf9be8b1df998f83df56a39ab264976bdb3307773e16f48"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"post-install": [
|
||||||
|
"install -Dm644 COPYING /app/share/licenses/libgusb/COPYING"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "libgusb",
|
||||||
|
"buildsystem": "meson",
|
||||||
|
"config-opts": [ "-Dtests=false", "-Dvapi=false", "-Ddocs=false", "-Dintrospection=false" ],
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"type": "archive",
|
||||||
|
"url": "https://github.com/hughsie/libgusb/archive/0.3.0.tar.gz",
|
||||||
|
"sha256": "b36310f8405d5fd68f6caf4a829f7ab4c627b38fd3d02a139d411fce0f3a49f1"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "libfprint",
|
||||||
|
"buildsystem": "meson",
|
||||||
|
"config-opts": [ "-Dudev_rules=false", "-Dx11-examples=false", "-Dgtk-examples=true", "-Ddrivers=all" ],
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://gitlab.freedesktop.org/libfprint/libfprint.git",
|
||||||
|
"branch": "wip/benzea/v2"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
BIN
demo/org.freedesktop.libfprint.Demo.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
@@ -60,21 +60,18 @@
|
|||||||
<para>
|
<para>
|
||||||
In summary, libfprint represents fingerprints in several internal structures
|
In summary, libfprint represents fingerprints in several internal structures
|
||||||
and each representation will offer you a way of determining the
|
and each representation will offer you a way of determining the
|
||||||
<ulink url="#driver_id">driver ID</ulink> and <ulink url="#device-types">devtype</ulink> of the print in
|
<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
|
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
|
match. libfprint does offer you some "is this print compatible?" helper
|
||||||
functions, so you don't have to worry about these details too much.
|
functions, so you don't have to worry about these details too much.
|
||||||
</para>
|
</para>
|
||||||
</refsect2>
|
</refsect2>
|
||||||
|
|
||||||
<refsect2 id="driver_id">
|
<refsect2 id="driver">
|
||||||
<title>Driver IDs</title>
|
<title>Driver</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Each driver is assigned a unique ID by the project maintainer. These
|
Each driver is assigned a unique string identifier by the project maintainer.
|
||||||
assignments are
|
|
||||||
<ulink url="https://gitlab.freedesktop.org/libfprint/libfprint/blob/master/libfprint/drivers/driver_ids.h">
|
|
||||||
documented in the sources</ulink> and will never change.
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@@ -89,22 +86,23 @@
|
|||||||
</para>
|
</para>
|
||||||
</refsect2>
|
</refsect2>
|
||||||
|
|
||||||
<refsect2 id="device-types">
|
<refsect2 id="device-id">
|
||||||
<title>Device types</title>
|
<title>Device ID</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Internally, the <ulink url="libfprint-Driver-operations.html#libfprint-Driver-operations.description">driver</ulink> behind a device assigns a 32-bit
|
Internally, the behind a device assigns a string identifier to the device
|
||||||
<emphasis>devtype</emphasis> identifier to the device. This cannot be used as a unique
|
This cannot be used as a unique ID for a specific device as many devices
|
||||||
ID for a specific device as many devices under the same range may share
|
under the same range may share the same devtype. The device ID may even
|
||||||
the same devtype. The devtype may even be 0 in all cases.
|
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>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The only reason you may be interested in retrieving the devtype for a
|
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
|
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
|
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
|
print you are verifying is compatible with the device in question - the
|
||||||
devtypes must be equal. This effectively allows drivers to support more
|
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
|
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
|
the other. Note that libfprint does provide you with helper functions to
|
||||||
determine whether a print is compatible with a device, so under most
|
determine whether a print is compatible with a device, so under most
|
||||||
|
|||||||
@@ -13,12 +13,12 @@
|
|||||||
|
|
||||||
<para>
|
<para>
|
||||||
Usually the first thing you want to do is determine which fingerprint
|
Usually the first thing you want to do is determine which fingerprint
|
||||||
devices are present. This is done through <ulink url="libfprint-Device-discovery.html">device discovery</ulink>.
|
devices are present. This is done using the <ulink url="fp-context.html">FpContext</ulink> object.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Once you have found a device you would like to operate, you should open it.
|
Once you have found a device you would like to operate, you should open it.
|
||||||
Refer to <ulink url="libfprint-Devices-operations.html">device operations</ulink>. This section also details enrollment,
|
Refer to <ulink url="fp-context.html">device operations</ulink>. This section also details enrollment,
|
||||||
image capture, and verification.
|
image capture, and verification.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
<para>This document is the API reference for the libfprint library.</para>
|
<para>This document is the API reference for the libfprint library.</para>
|
||||||
<para>
|
<para>
|
||||||
The latest version of libfprint, as well as the latest version of
|
The latest version of libfprint, as well as the latest version of
|
||||||
this API reference, is <ulink role="online-location" url="https://www.freedesktop.org/wiki/Software/fprint/libfprint/">available online</ulink>.
|
this API reference, is <ulink role="online-location" url="https://fprint.freedesktop.org/libfprint-dev/">available online</ulink>.
|
||||||
</para>
|
</para>
|
||||||
</releaseinfo>
|
</releaseinfo>
|
||||||
</bookinfo>
|
</bookinfo>
|
||||||
@@ -24,23 +24,45 @@
|
|||||||
</part>
|
</part>
|
||||||
|
|
||||||
<part>
|
<part>
|
||||||
<title>API Documentation</title>
|
<title>Library API Documentation</title>
|
||||||
<xi:include href="xml/events.xml"/>
|
<xi:include href="xml/fp-context.xml"/>
|
||||||
<xi:include href="xml/discovery.xml"/>
|
<xi:include href="xml/fp-device.xml"/>
|
||||||
|
<xi:include href="xml/fp-image-device.xml"/>
|
||||||
<xi:include href="xml/drv.xml"/>
|
<xi:include href="xml/fp-print.xml"/>
|
||||||
<xi:include href="xml/dev.xml"/>
|
<xi:include href="xml/fp-image.xml"/>
|
||||||
<xi:include href="xml/print_data.xml"/>
|
|
||||||
<!-- FIXME https://bugs.freedesktop.org/show_bug.cgi?id=106550 -->
|
|
||||||
<xi:include href="xml/dscv_print.xml"/>
|
|
||||||
<xi:include href="xml/img.xml"/>
|
|
||||||
</part>
|
</part>
|
||||||
|
|
||||||
<!--
|
|
||||||
<part>
|
<part>
|
||||||
<title>Writing Drivers</title>
|
<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 and State Machine helpers</title>
|
||||||
|
<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>
|
</part>
|
||||||
-->
|
|
||||||
|
|
||||||
<index id="api-index">
|
<index id="api-index">
|
||||||
<title>API Index</title>
|
<title>API Index</title>
|
||||||
|
|||||||
@@ -1,136 +1,260 @@
|
|||||||
<INCLUDE>fprint.h</INCLUDE>
|
|
||||||
|
|
||||||
<SECTION>
|
<SECTION>
|
||||||
<FILE>events</FILE>
|
<FILE>drivers_api</FILE>
|
||||||
<TITLE>Initialisation and events handling</TITLE>
|
|
||||||
fp_set_debug
|
|
||||||
fp_init
|
|
||||||
fp_exit
|
|
||||||
fp_pollfd
|
|
||||||
fp_handle_events_timeout
|
|
||||||
fp_handle_events
|
|
||||||
fp_get_next_timeout
|
|
||||||
fp_get_pollfds
|
|
||||||
fp_pollfd_added_cb
|
|
||||||
fp_pollfd_removed_cb
|
|
||||||
fp_set_pollfd_notifiers
|
|
||||||
</SECTION>
|
</SECTION>
|
||||||
|
|
||||||
<SECTION>
|
<SECTION>
|
||||||
<FILE>discovery</FILE>
|
<FILE>fp-context</FILE>
|
||||||
<TITLE>Device discovery</TITLE>
|
<TITLE>FpContext</TITLE>
|
||||||
fp_dscv_dev
|
FP_TYPE_CONTEXT
|
||||||
fp_discover_devs
|
FpContextClass
|
||||||
fp_dscv_devs_free
|
fp_context_new
|
||||||
fp_dscv_dev_get_driver
|
fp_context_enumerate
|
||||||
fp_dscv_dev_get_devtype
|
fp_context_get_devices
|
||||||
fp_dscv_dev_get_driver_id
|
FpContext
|
||||||
fp_dscv_dev_supports_print_data
|
|
||||||
fp_dscv_dev_supports_dscv_print
|
|
||||||
fp_dscv_dev_for_print_data
|
|
||||||
fp_dscv_dev_for_dscv_print
|
|
||||||
</SECTION>
|
</SECTION>
|
||||||
|
|
||||||
<SECTION>
|
<SECTION>
|
||||||
<FILE>drv</FILE>
|
<FILE>fp-device</FILE>
|
||||||
fp_driver
|
FP_TYPE_DEVICE
|
||||||
fp_driver_get_name
|
FP_DEVICE_RETRY
|
||||||
fp_driver_get_full_name
|
FP_DEVICE_ERROR
|
||||||
fp_driver_get_driver_id
|
FpDeviceType
|
||||||
fp_driver_get_scan_type
|
FpScanType
|
||||||
|
FpDeviceRetry
|
||||||
|
FpDeviceError
|
||||||
|
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_has_storage
|
||||||
|
fp_device_supports_identify
|
||||||
|
fp_device_supports_capture
|
||||||
|
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_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_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
|
||||||
|
FpDevice
|
||||||
</SECTION>
|
</SECTION>
|
||||||
|
|
||||||
<SECTION>
|
<SECTION>
|
||||||
<FILE>dev</FILE>
|
<FILE>fp-image</FILE>
|
||||||
fp_dev
|
FP_TYPE_IMAGE
|
||||||
fp_scan_type
|
FpMinutia
|
||||||
fp_capture_result
|
fp_image_new
|
||||||
fp_enroll_result
|
fp_image_get_width
|
||||||
fp_verify_result
|
fp_image_get_height
|
||||||
|
fp_image_get_ppmm
|
||||||
fp_dev_get_driver
|
fp_image_get_minutiae
|
||||||
fp_dev_get_nr_enroll_stages
|
fp_image_detect_minutiae
|
||||||
fp_dev_get_devtype
|
fp_image_detect_minutiae_finish
|
||||||
fp_dev_supports_print_data
|
fp_image_get_data
|
||||||
fp_dev_supports_imaging
|
fp_image_get_binarized
|
||||||
fp_dev_supports_identification
|
fp_minutia_get_coords
|
||||||
fp_dev_supports_dscv_print
|
FpImage
|
||||||
fp_dev_get_img_width
|
|
||||||
fp_dev_get_img_height
|
|
||||||
|
|
||||||
fp_operation_stop_cb
|
|
||||||
fp_img_operation_cb
|
|
||||||
fp_dev_open_cb
|
|
||||||
fp_enroll_stage_cb
|
|
||||||
fp_identify_cb
|
|
||||||
|
|
||||||
fp_dev_open
|
|
||||||
fp_async_dev_open
|
|
||||||
|
|
||||||
fp_dev_close
|
|
||||||
fp_async_dev_close
|
|
||||||
|
|
||||||
fp_enroll_finger
|
|
||||||
fp_enroll_finger_img
|
|
||||||
fp_async_enroll_start
|
|
||||||
fp_async_enroll_stop
|
|
||||||
|
|
||||||
fp_verify_finger
|
|
||||||
fp_verify_finger_img
|
|
||||||
fp_async_verify_start
|
|
||||||
fp_async_verify_stop
|
|
||||||
|
|
||||||
fp_identify_finger
|
|
||||||
fp_identify_finger_img
|
|
||||||
fp_async_identify_start
|
|
||||||
fp_async_identify_stop
|
|
||||||
|
|
||||||
fp_dev_img_capture
|
|
||||||
fp_async_capture_start
|
|
||||||
fp_async_capture_stop
|
|
||||||
</SECTION>
|
</SECTION>
|
||||||
|
|
||||||
<SECTION>
|
<SECTION>
|
||||||
<FILE>print_data</FILE>
|
<FILE>fp-image-device</FILE>
|
||||||
fp_finger
|
FP_TYPE_IMAGE_DEVICE
|
||||||
fp_print_data
|
FpImageDevice
|
||||||
fp_print_data
|
|
||||||
fp_print_data_get_data
|
|
||||||
fp_print_data_from_data
|
|
||||||
fp_print_data_save
|
|
||||||
fp_print_data_load
|
|
||||||
fp_print_data_delete
|
|
||||||
fp_print_data_from_dscv_print
|
|
||||||
fp_print_data_free
|
|
||||||
fp_print_data_get_driver_id
|
|
||||||
fp_print_data_get_devtype
|
|
||||||
</SECTION>
|
</SECTION>
|
||||||
|
|
||||||
<SECTION>
|
<SECTION>
|
||||||
<FILE>dscv_print</FILE>
|
<FILE>fp-print</FILE>
|
||||||
fp_dscv_print
|
FP_TYPE_PRINT
|
||||||
fp_discover_prints
|
FpFinger
|
||||||
fp_dscv_prints_free
|
FpPrint
|
||||||
fp_dscv_print_get_driver_id
|
fp_print_new
|
||||||
fp_dscv_print_get_devtype
|
fp_print_new_from_data
|
||||||
fp_dscv_print_get_finger
|
fp_print_to_data
|
||||||
fp_dscv_print_delete
|
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>
|
||||||
|
|
||||||
<SECTION>
|
<SECTION>
|
||||||
<FILE>img</FILE>
|
<FILE>fpi-assembling</FILE>
|
||||||
fp_img
|
fpi_frame
|
||||||
fp_minutia
|
fpi_frame_asmbl_ctx
|
||||||
fp_img_free
|
fpi_do_movement_estimation
|
||||||
fp_img_get_height
|
fpi_assemble_frames
|
||||||
fp_img_get_width
|
fpi_line_asmbl_ctx
|
||||||
fp_img_get_data
|
fpi_assemble_lines
|
||||||
fp_img_save_to_file
|
|
||||||
fp_img_standardize
|
|
||||||
fp_img_binarize
|
|
||||||
fp_img_get_minutiae
|
|
||||||
</SECTION>
|
</SECTION>
|
||||||
|
|
||||||
<SECTION>
|
<SECTION>
|
||||||
<FILE>poll</FILE>
|
<FILE>fpi-context</FILE>
|
||||||
|
fpi_get_driver_types
|
||||||
</SECTION>
|
</SECTION>
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<FILE>fpi-device</FILE>
|
||||||
|
FpDeviceClass
|
||||||
|
FpTimeoutFunc
|
||||||
|
FpiDeviceAction
|
||||||
|
FpIdEntry
|
||||||
|
fpi_device_get_usb_device
|
||||||
|
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_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_delete_complete
|
||||||
|
fpi_device_enroll_progress
|
||||||
|
fpi_device_verify_report
|
||||||
|
fpi_device_identify_report
|
||||||
|
</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>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
|
||||||
|
</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
|
||||||
|
</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_error
|
||||||
|
fpi_ssm_dup_error
|
||||||
|
fpi_ssm_get_cur_state
|
||||||
|
fpi_ssm_next_state_timeout_cb
|
||||||
|
fpi_ssm_usb_transfer_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>
|
||||||
|
|
||||||
|
|||||||
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>
|
||||||
@@ -2,36 +2,12 @@ subdir('xml')
|
|||||||
|
|
||||||
private_headers = [
|
private_headers = [
|
||||||
'config.h',
|
'config.h',
|
||||||
|
'nbis-helpers.h',
|
||||||
|
'fprint.h',
|
||||||
|
|
||||||
'aeslib.h',
|
# Subdirectories to ignore
|
||||||
'assembling.h',
|
'drivers',
|
||||||
'fp_internal.h',
|
'nbis',
|
||||||
|
|
||||||
# Drivers
|
|
||||||
'aes1660.h',
|
|
||||||
'aes2501.h',
|
|
||||||
'aes2550.h',
|
|
||||||
'aes2660.h',
|
|
||||||
'aes3k.h',
|
|
||||||
'aesx660.h',
|
|
||||||
'driver_ids.h',
|
|
||||||
'elan.h',
|
|
||||||
'upeksonly.h',
|
|
||||||
'upektc.h',
|
|
||||||
'upektc_img.h',
|
|
||||||
'vfs0050.h',
|
|
||||||
'vfs301_proto_fragments.h',
|
|
||||||
'vfs301_proto.h',
|
|
||||||
'vfs5011_proto.h',
|
|
||||||
|
|
||||||
# NBIS
|
|
||||||
'morph.h',
|
|
||||||
'sunrast.h',
|
|
||||||
'bozorth.h',
|
|
||||||
'defs.h',
|
|
||||||
'log.h',
|
|
||||||
'bz_array.h',
|
|
||||||
'lfs.h',
|
|
||||||
]
|
]
|
||||||
|
|
||||||
html_images = [
|
html_images = [
|
||||||
@@ -47,17 +23,13 @@ glib_prefix = dependency('glib-2.0').get_pkgconfig_variable('prefix')
|
|||||||
glib_docpath = join_paths(glib_prefix, 'share', 'gtk-doc', 'html')
|
glib_docpath = join_paths(glib_prefix, 'share', 'gtk-doc', 'html')
|
||||||
docpath = join_paths(get_option('datadir'), 'gtk-doc', 'html')
|
docpath = join_paths(get_option('datadir'), 'gtk-doc', 'html')
|
||||||
|
|
||||||
gnome.gtkdoc('libfprint',
|
gnome.gtkdoc(versioned_libname,
|
||||||
main_xml: 'libfprint-docs.xml',
|
main_xml: 'libfprint-docs.xml',
|
||||||
src_dir: join_paths(meson.source_root(), 'libfprint'),
|
src_dir: join_paths(meson.source_root(), 'libfprint'),
|
||||||
dependencies: libfprint_dep,
|
dependencies: libfprint_dep,
|
||||||
content_files: content_files,
|
content_files: content_files,
|
||||||
expand_content_files: expand_content_files,
|
expand_content_files: expand_content_files,
|
||||||
scan_args: [
|
ignore_headers: private_headers,
|
||||||
'--rebuild-types',
|
|
||||||
'--ignore-decorators=API_EXPORTED',
|
|
||||||
'--ignore-headers=' + ' '.join(private_headers),
|
|
||||||
],
|
|
||||||
fixxref_args: [
|
fixxref_args: [
|
||||||
'--html-dir=@0@'.format(docpath),
|
'--html-dir=@0@'.format(docpath),
|
||||||
'--extra-dir=@0@'.format(join_paths(glib_docpath, 'glib')),
|
'--extra-dir=@0@'.format(join_paths(glib_docpath, 'glib')),
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
ent_conf = configuration_data()
|
ent_conf = configuration_data()
|
||||||
ent_conf.set('PACKAGE', 'libfprint')
|
ent_conf.set('PACKAGE', versioned_libname)
|
||||||
ent_conf.set('PACKAGE_BUGREPORT', 'https://bugs.freedesktop.org/enter_bug.cgi?product=libfprint')
|
ent_conf.set('PACKAGE_BUGREPORT', 'https://gitlab.freedesktop.org/libfprint/libfprint/issues')
|
||||||
ent_conf.set('PACKAGE_NAME', 'libfprint')
|
ent_conf.set('PACKAGE_NAME', versioned_libname)
|
||||||
ent_conf.set('PACKAGE_STRING', 'libfprint')
|
ent_conf.set('PACKAGE_STRING', versioned_libname)
|
||||||
ent_conf.set('PACKAGE_TARNAME', 'libfprint-' + meson.project_version())
|
ent_conf.set('PACKAGE_TARNAME', 'libfprint-' + meson.project_version())
|
||||||
ent_conf.set('PACKAGE_URL', 'https://www.freedesktop.org/wiki/Software/fprint/libfprint/')
|
ent_conf.set('PACKAGE_URL', 'https://fprint.freedesktop.org/')
|
||||||
ent_conf.set('PACKAGE_VERSION', meson.project_version())
|
ent_conf.set('PACKAGE_VERSION', meson.project_version())
|
||||||
ent_conf.set('PACKAGE_API_VERSION', '1.0')
|
ent_conf.set('PACKAGE_API_VERSION', '1.0')
|
||||||
configure_file(input: 'gtkdocentities.ent.in', output: 'gtkdocentities.ent', configuration: ent_conf)
|
configure_file(input: 'gtkdocentities.ent.in',
|
||||||
|
output: 'gtkdocentities.ent',
|
||||||
|
configuration: ent_conf)
|
||||||
|
|||||||
@@ -6,6 +6,10 @@
|
|||||||
|
|
||||||
int main (int argc, char **argv)
|
int main (int argc, char **argv)
|
||||||
{
|
{
|
||||||
fp_init ();
|
FpContext *ctx;
|
||||||
|
|
||||||
|
ctx = fp_context_new ();
|
||||||
|
g_object_unref (ctx);
|
||||||
|
|
||||||
return 0;
|
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 choosen 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,141 +19,180 @@
|
|||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#define FP_COMPONENT "example-enroll"
|
||||||
#include <stdlib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
#include <libfprint/fprint.h>
|
#include <libfprint/fprint.h>
|
||||||
|
|
||||||
struct fp_dscv_dev *discover_device(struct fp_dscv_dev **discovered_devs)
|
#include "storage.h"
|
||||||
{
|
#include "utilities.h"
|
||||||
struct fp_dscv_dev *ddev = discovered_devs[0];
|
|
||||||
struct fp_driver *drv;
|
|
||||||
if (!ddev)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
drv = fp_dscv_dev_get_driver(ddev);
|
typedef struct _EnrollData
|
||||||
printf("Found device claimed by %s driver\n", fp_driver_get_full_name(drv));
|
{
|
||||||
return ddev;
|
GMainLoop *loop;
|
||||||
|
FpFinger finger;
|
||||||
|
int ret_value;
|
||||||
|
} EnrollData;
|
||||||
|
|
||||||
|
static void
|
||||||
|
enroll_data_free (EnrollData *enroll_data)
|
||||||
|
{
|
||||||
|
g_main_loop_unref (enroll_data->loop);
|
||||||
|
g_free (enroll_data);
|
||||||
|
}
|
||||||
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC (EnrollData, enroll_data_free)
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_device_closed (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||||
|
{
|
||||||
|
EnrollData *enroll_data = user_data;
|
||||||
|
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
|
||||||
|
fp_device_close_finish (dev, res, &error);
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
g_warning ("Failed closing device %s\n", error->message);
|
||||||
|
|
||||||
|
g_main_loop_quit (enroll_data->loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct fp_print_data *enroll(struct fp_dev *dev) {
|
static void
|
||||||
struct fp_print_data *enrolled_print = NULL;
|
on_enroll_completed (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||||
int r;
|
{
|
||||||
|
EnrollData *enroll_data = user_data;
|
||||||
|
|
||||||
printf("You will need to successfully scan your finger %d times to "
|
g_autoptr(FpPrint) print = NULL;
|
||||||
"complete the process.\n", fp_dev_get_nr_enroll_stages(dev));
|
g_autoptr(GError) error = NULL;
|
||||||
|
|
||||||
do {
|
print = fp_device_enroll_finish (dev, res, &error);
|
||||||
struct fp_img *img = NULL;
|
|
||||||
|
|
||||||
sleep(1);
|
if (!error)
|
||||||
printf("\nScan your finger now.\n");
|
{
|
||||||
|
enroll_data->ret_value = EXIT_SUCCESS;
|
||||||
|
|
||||||
r = fp_enroll_finger_img(dev, &enrolled_print, &img);
|
if (!fp_device_has_storage (dev))
|
||||||
if (img) {
|
{
|
||||||
fp_img_save_to_file(img, "enrolled.pgm");
|
g_debug ("Device has not storage, saving locally");
|
||||||
|
int r = print_data_save (print, enroll_data->finger);
|
||||||
|
if (r < 0)
|
||||||
|
{
|
||||||
|
g_warning ("Data save failed, code %d", r);
|
||||||
|
enroll_data->ret_value = EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_warning ("Enroll failed with error %s\n", 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 (fp_device_supports_capture (device) &&
|
||||||
|
print_image_save (print, "enrolled.pgm"))
|
||||||
printf ("Wrote scanned image to enrolled.pgm\n");
|
printf ("Wrote scanned image to enrolled.pgm\n");
|
||||||
fp_img_free(img);
|
|
||||||
}
|
printf ("Enroll stage %d of %d passed. Yay!\n", completed_stages,
|
||||||
if (r < 0) {
|
fp_device_get_nr_enroll_stages (device));
|
||||||
printf("Enroll failed with error %d\n", r);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (r) {
|
static void
|
||||||
case FP_ENROLL_COMPLETE:
|
on_device_opened (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||||
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;
|
EnrollData *enroll_data = user_data;
|
||||||
struct fp_dscv_dev *ddev;
|
FpPrint *print_template;
|
||||||
struct fp_dscv_dev **discovered_devs;
|
|
||||||
struct fp_dev *dev;
|
|
||||||
struct fp_print_data *data;
|
|
||||||
|
|
||||||
printf("This program will enroll your right index finger, "
|
g_autoptr(GError) error = NULL;
|
||||||
"unconditionally overwriting any right-index print that was enrolled "
|
|
||||||
|
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. 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);
|
||||||
|
fp_device_enroll (dev, print_template, NULL, on_enroll_progress, NULL,
|
||||||
|
NULL, (GAsyncReadyCallback) on_enroll_completed,
|
||||||
|
enroll_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
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, unconditionally "
|
||||||
|
"overwriting any print for the same finger that was enrolled "
|
||||||
"previously. If you want to continue, press enter, otherwise hit "
|
"previously. If you want to continue, press enter, otherwise hit "
|
||||||
"Ctrl+C\n");
|
"Ctrl+C\n");
|
||||||
getchar ();
|
getchar ();
|
||||||
|
|
||||||
|
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);
|
setenv ("G_MESSAGES_DEBUG", "all", 0);
|
||||||
setenv ("LIBUSB_DEBUG", "3", 0);
|
|
||||||
|
|
||||||
r = fp_init();
|
ctx = fp_context_new ();
|
||||||
if (r < 0) {
|
|
||||||
fprintf(stderr, "Failed to initialize libfprint\n");
|
devices = fp_context_get_devices (ctx);
|
||||||
exit(1);
|
if (!devices)
|
||||||
|
{
|
||||||
|
g_warning ("Impossible to get devices");
|
||||||
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
discovered_devs = fp_discover_devs();
|
dev = discover_device (devices);
|
||||||
if (!discovered_devs) {
|
if (!dev)
|
||||||
fprintf(stderr, "Could not discover devices\n");
|
{
|
||||||
goto out;
|
g_warning ("No devices detected.");
|
||||||
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
ddev = discover_device(discovered_devs);
|
enroll_data = g_new0 (EnrollData, 1);
|
||||||
if (!ddev) {
|
enroll_data->finger = finger;
|
||||||
fprintf(stderr, "No devices detected.\n");
|
enroll_data->ret_value = EXIT_FAILURE;
|
||||||
goto out;
|
enroll_data->loop = g_main_loop_new (NULL, FALSE);
|
||||||
|
|
||||||
|
fp_device_open (dev, NULL, (GAsyncReadyCallback) on_device_opened,
|
||||||
|
enroll_data);
|
||||||
|
|
||||||
|
g_main_loop_run (enroll_data->loop);
|
||||||
|
|
||||||
|
return enroll_data->ret_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,108 +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;
|
|
||||||
|
|
||||||
setenv ("G_MESSAGES_DEBUG", "all", 0);
|
|
||||||
setenv ("LIBUSB_DEBUG", "3", 0);
|
|
||||||
|
|
||||||
r = fp_init();
|
|
||||||
if (r < 0) {
|
|
||||||
fprintf(stderr, "Failed to initialize libfprint\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
discovered_devs = fp_discover_devs();
|
|
||||||
if (!discovered_devs) {
|
|
||||||
fprintf(stderr, "Could not discover devices\n");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
ddev = discover_device(discovered_devs);
|
|
||||||
if (!ddev) {
|
|
||||||
fp_dscv_devs_free(discovered_devs);
|
|
||||||
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,261 +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;
|
|
||||||
uint64_t 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(void)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
|
|
||||||
setenv ("G_MESSAGES_DEBUG", "all", 0);
|
|
||||||
setenv ("LIBUSB_DEBUG", "3", 0);
|
|
||||||
|
|
||||||
r = fp_init();
|
|
||||||
if (r < 0) {
|
|
||||||
fprintf(stderr, "Failed to initialize libfprint\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
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\n", 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\n", 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_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_storage (dev))
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
@@ -1,29 +1,16 @@
|
|||||||
|
|
||||||
examples = [ 'verify_live', 'enroll', 'verify', 'img_capture' ]
|
examples = [ 'enroll', 'verify', 'manage-prints' ]
|
||||||
foreach example: examples
|
foreach example: examples
|
||||||
executable(example,
|
executable(example,
|
||||||
example + '.c',
|
[ example + '.c', 'storage.c', 'utilities.c' ],
|
||||||
dependencies: libfprint_dep,
|
dependencies: [
|
||||||
include_directories: [
|
libfprint_dep,
|
||||||
root_inc,
|
glib_dep,
|
||||||
],
|
],
|
||||||
c_args: common_cflags)
|
)
|
||||||
endforeach
|
endforeach
|
||||||
|
|
||||||
executable('cpp-test',
|
executable('cpp-test',
|
||||||
'cpp-test.cpp',
|
'cpp-test.cpp',
|
||||||
dependencies: libfprint_dep,
|
dependencies: libfprint_dep,
|
||||||
include_directories: [
|
)
|
||||||
root_inc,
|
|
||||||
],
|
|
||||||
c_args: common_cflags)
|
|
||||||
|
|
||||||
if get_option('x11-examples')
|
|
||||||
executable('img_capture_continuous',
|
|
||||||
'img_capture_continuous.c',
|
|
||||||
dependencies: [ libfprint_dep, xv_dep, x11_dep ],
|
|
||||||
include_directories: [
|
|
||||||
root_inc,
|
|
||||||
],
|
|
||||||
c_args: common_cflags)
|
|
||||||
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)
|
||||||
|
|
||||||
234
examples/storage.c
Normal file
@@ -0,0 +1,234 @@
|
|||||||
|
/*
|
||||||
|
* Trivial storage driver for example programs
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
||||||
|
* Copyright (C) 2019 Marco Trevisan <marco.trevisan@canonical.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define FP_COMPONENT "example-storage"
|
||||||
|
|
||||||
|
#include <libfprint/fprint.h>
|
||||||
|
#include <libfprint/fpi-compat.h>
|
||||||
|
#include "storage.h"
|
||||||
|
|
||||||
|
#include <errno.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 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
print_data_save (FpPrint *print, FpFinger finger)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
const guchar *stored_data = NULL;
|
||||||
|
gsize stored_len;
|
||||||
|
|
||||||
|
dict = load_data ();
|
||||||
|
val = g_variant_dict_lookup_value (dict, descr, G_VARIANT_TYPE ("ay"));
|
||||||
|
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
FpPrint *print;
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
|
||||||
|
stored_data = (const guchar *) g_variant_get_fixed_array (val, &stored_len, 1);
|
||||||
|
print = fp_print_deserialize (stored_data, stored_len, &error);
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
g_warning ("Error deserializing data: %s", error->message);
|
||||||
|
|
||||||
|
return print;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
FpPrint *
|
||||||
|
print_create_template (FpDevice *dev, FpFinger finger)
|
||||||
|
{
|
||||||
|
g_autoptr(GDateTime) datetime = NULL;
|
||||||
|
g_autoptr(GDate) date = NULL;
|
||||||
|
FpPrint *template = NULL;
|
||||||
|
gint year, month, day;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static 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;
|
||||||
|
}
|
||||||
30
examples/storage.h
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
int print_data_save (FpPrint *print,
|
||||||
|
FpFinger finger);
|
||||||
|
FpPrint * print_data_load (FpDevice *dev,
|
||||||
|
FpFinger finger);
|
||||||
|
FpPrint * print_create_template (FpDevice *dev,
|
||||||
|
FpFinger finger);
|
||||||
|
gboolean print_image_save (FpPrint *print,
|
||||||
|
const char *path);
|
||||||
127
examples/utilities.c
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
/*
|
||||||
|
* 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";
|
||||||
|
|
||||||
|
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,130 +19,298 @@
|
|||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#define FP_COMPONENT "example-verify"
|
||||||
#include <stdlib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
#include <libfprint/fprint.h>
|
#include <libfprint/fprint.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;
|
FpFinger finger;
|
||||||
if (!ddev)
|
int ret_value;
|
||||||
return NULL;
|
} VerifyData;
|
||||||
|
|
||||||
drv = fp_dscv_dev_get_driver(ddev);
|
static void
|
||||||
printf("Found device claimed by %s driver\n", fp_driver_get_full_name(drv));
|
verify_data_free (VerifyData *verify_data)
|
||||||
return ddev;
|
|
||||||
}
|
|
||||||
|
|
||||||
int verify(struct fp_dev *dev, struct fp_print_data *data)
|
|
||||||
{
|
{
|
||||||
int r;
|
g_main_loop_unref (verify_data->loop);
|
||||||
|
g_free (verify_data);
|
||||||
|
}
|
||||||
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC (VerifyData, verify_data_free)
|
||||||
|
|
||||||
do {
|
static void
|
||||||
struct fp_img *img = NULL;
|
on_device_closed (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
int r = 1;
|
VerifyData *verify_data = user_data;
|
||||||
struct fp_dscv_dev *ddev;
|
|
||||||
struct fp_dscv_dev **discovered_devs;
|
g_autoptr(GError) error = NULL;
|
||||||
struct fp_dev *dev;
|
|
||||||
struct fp_print_data *data;
|
fp_device_close_finish (dev, res, &error);
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
g_warning ("Failed closing device %s\n", error->message);
|
||||||
|
|
||||||
|
g_main_loop_quit (verify_data->loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
verify_quit (FpDevice *dev,
|
||||||
|
VerifyData *verify_data)
|
||||||
|
{
|
||||||
|
if (!fp_device_is_open (dev))
|
||||||
|
{
|
||||||
|
g_main_loop_quit (verify_data->loop);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed, verify_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void start_verification (FpDevice *dev,
|
||||||
|
VerifyData *verify_data);
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_verify_completed (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||||
|
{
|
||||||
|
VerifyData *verify_data = user_data;
|
||||||
|
|
||||||
|
g_autoptr(FpPrint) print = NULL;
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
char buffer[20];
|
||||||
|
gboolean match;
|
||||||
|
|
||||||
|
if (!fp_device_verify_finish (dev, res, &match, &print, &error))
|
||||||
|
{
|
||||||
|
g_warning ("Failed to verify print: %s", error->message);
|
||||||
|
verify_data->ret_value = EXIT_FAILURE;
|
||||||
|
|
||||||
|
if (error->domain != FP_DEVICE_RETRY)
|
||||||
|
{
|
||||||
|
verify_quit (dev, verify_data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_print ("Verify again? [Y/n]? ");
|
||||||
|
if (fgets (buffer, sizeof (buffer), stdin) &&
|
||||||
|
(buffer[0] == 'Y' || buffer[0] == 'y' || buffer[0] == '\n'))
|
||||||
|
{
|
||||||
|
start_verification (dev, verify_data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
verify_quit (dev, verify_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_match_cb (FpDevice *dev, FpPrint *match, FpPrint *print,
|
||||||
|
gpointer user_data, GError *error)
|
||||||
|
{
|
||||||
|
VerifyData *verify_data = user_data;
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
g_warning ("Match report: Finger not matched, retry error reported: %s",
|
||||||
|
error->message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (print && fp_device_supports_capture (dev) &&
|
||||||
|
print_image_save (print, "verify.pgm"))
|
||||||
|
g_print ("Print image saved as verify.pgm\n");
|
||||||
|
|
||||||
|
if (match)
|
||||||
|
{
|
||||||
|
char date_str[128];
|
||||||
|
|
||||||
|
verify_data->ret_value = EXIT_SUCCESS;
|
||||||
|
|
||||||
|
g_date_strftime (date_str, G_N_ELEMENTS (date_str), "%Y-%m-%d\0",
|
||||||
|
fp_print_get_enroll_date (match));
|
||||||
|
g_debug ("Match report: device %s matched finger %s successifully "
|
||||||
|
"with print %s, enrolled on date %s by user %s",
|
||||||
|
fp_device_get_name (dev),
|
||||||
|
finger_to_string (fp_print_get_finger (match)),
|
||||||
|
fp_print_get_description (match), date_str,
|
||||||
|
fp_print_get_username (match));
|
||||||
|
|
||||||
|
g_print ("MATCH!\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_debug ("Match report: Finger not matched");
|
||||||
|
g_print ("NO MATCH!\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static 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;
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
if (!prints->len)
|
||||||
|
g_warning ("No prints saved on device");
|
||||||
|
|
||||||
|
for (i = 0; i < prints->len; ++i)
|
||||||
|
{
|
||||||
|
FpPrint *print = prints->pdata[i];
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
g_warning ("Did you remember to enroll your %s finger first?",
|
||||||
|
finger_to_string (verify_data->finger));
|
||||||
|
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, NULL,
|
||||||
|
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_storage (dev))
|
||||||
|
{
|
||||||
|
g_print ("Creating finger template, using device storage...\n");
|
||||||
|
fp_device_list_prints (dev, NULL,
|
||||||
|
(GAsyncReadyCallback) on_list_completed,
|
||||||
|
verify_data);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_print ("Loading previously enrolled %s finger data...\n",
|
||||||
|
finger_to_string (verify_data->finger));
|
||||||
|
g_autoptr(FpPrint) verify_print = NULL;
|
||||||
|
|
||||||
|
verify_print = print_data_load (dev, verify_data->finger);
|
||||||
|
|
||||||
|
if (!verify_print)
|
||||||
|
{
|
||||||
|
g_warning ("Failed to load fingerprint data");
|
||||||
|
g_warning ("Did you remember to enroll your %s finger first?",
|
||||||
|
finger_to_string (verify_data->finger));
|
||||||
|
verify_quit (dev, verify_data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_print ("Print loaded. Time to verify!\n");
|
||||||
|
fp_device_verify (dev, verify_print, NULL,
|
||||||
|
NULL, NULL, 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 ("G_MESSAGES_DEBUG", "all", 0);
|
||||||
setenv ("LIBUSB_DEBUG", "3", 0);
|
setenv ("LIBUSB_DEBUG", "3", 0);
|
||||||
|
|
||||||
r = fp_init();
|
ctx = fp_context_new ();
|
||||||
if (r < 0) {
|
|
||||||
fprintf(stderr, "Failed to initialize libfprint\n");
|
devices = fp_context_get_devices (ctx);
|
||||||
exit(1);
|
if (!devices)
|
||||||
|
{
|
||||||
|
g_warning ("Impossible to get devices");
|
||||||
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
discovered_devs = fp_discover_devs();
|
dev = discover_device (devices);
|
||||||
if (!discovered_devs) {
|
if (!dev)
|
||||||
fprintf(stderr, "Could not discover devices\n");
|
{
|
||||||
goto out;
|
g_warning ("No devices detected.");
|
||||||
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
ddev = discover_device(discovered_devs);
|
verify_data = g_new0 (VerifyData, 1);
|
||||||
if (!ddev) {
|
verify_data->ret_value = EXIT_FAILURE;
|
||||||
fprintf(stderr, "No devices detected.\n");
|
verify_data->loop = g_main_loop_new (NULL, FALSE);
|
||||||
goto out;
|
|
||||||
|
fp_device_open (dev, NULL, (GAsyncReadyCallback) on_device_opened,
|
||||||
|
verify_data);
|
||||||
|
|
||||||
|
g_main_loop_run (verify_data->loop);
|
||||||
|
|
||||||
|
return verify_data->ret_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
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. Loading previously enrolled right index finger "
|
|
||||||
"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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,189 +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;
|
|
||||||
|
|
||||||
setenv ("G_MESSAGES_DEBUG", "all", 0);
|
|
||||||
setenv ("LIBUSB_DEBUG", "3", 0);
|
|
||||||
|
|
||||||
r = fp_init();
|
|
||||||
if (r < 0) {
|
|
||||||
fprintf(stderr, "Failed to initialize libfprint\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
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,175 +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 "fp_internal.h"
|
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <libusb.h>
|
|
||||||
#include <glib.h>
|
|
||||||
|
|
||||||
#include "assembling.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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
@@ -1,434 +0,0 @@
|
|||||||
/*
|
|
||||||
* Image assembling routines
|
|
||||||
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
|
||||||
* Copyright (C) 2013 Arseniy Lartsev <arseniy@chalmers.se>
|
|
||||||
* Copyright (C) 2015 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 "assembling"
|
|
||||||
|
|
||||||
#include "fp_internal.h"
|
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <libusb.h>
|
|
||||||
#include <glib.h>
|
|
||||||
|
|
||||||
#include "assembling.h"
|
|
||||||
|
|
||||||
static unsigned int calc_error(struct fpi_frame_asmbl_ctx *ctx,
|
|
||||||
struct fpi_frame *first_frame,
|
|
||||||
struct fpi_frame *second_frame,
|
|
||||||
int dx,
|
|
||||||
int dy)
|
|
||||||
{
|
|
||||||
unsigned int width, height;
|
|
||||||
unsigned int x1, y1, x2, y2, err, i, j;
|
|
||||||
|
|
||||||
width = ctx->frame_width - (dx > 0 ? dx : -dx);
|
|
||||||
height = ctx->frame_height - dy;
|
|
||||||
|
|
||||||
y1 = 0;
|
|
||||||
y2 = dy;
|
|
||||||
i = 0;
|
|
||||||
err = 0;
|
|
||||||
do {
|
|
||||||
x1 = dx < 0 ? 0 : dx;
|
|
||||||
x2 = dx < 0 ? -dx : 0;
|
|
||||||
j = 0;
|
|
||||||
|
|
||||||
do {
|
|
||||||
unsigned char v1, v2;
|
|
||||||
|
|
||||||
|
|
||||||
v1 = ctx->get_pixel(ctx, first_frame, x1, y1);
|
|
||||||
v2 = ctx->get_pixel(ctx, second_frame, x2, y2);
|
|
||||||
err += v1 > v2 ? v1 - v2 : v2 - v1;
|
|
||||||
j++;
|
|
||||||
x1++;
|
|
||||||
x2++;
|
|
||||||
|
|
||||||
} while (j < width);
|
|
||||||
i++;
|
|
||||||
y1++;
|
|
||||||
y2++;
|
|
||||||
} while (i < height);
|
|
||||||
|
|
||||||
/* Normalize error */
|
|
||||||
err *= (ctx->frame_height * ctx->frame_width);
|
|
||||||
err /= (height * width);
|
|
||||||
|
|
||||||
if (err == 0)
|
|
||||||
return INT_MAX;
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This function is rather CPU-intensive. It's better to use hardware
|
|
||||||
* to detect movement direction when possible.
|
|
||||||
*/
|
|
||||||
static void find_overlap(struct fpi_frame_asmbl_ctx *ctx,
|
|
||||||
struct fpi_frame *first_frame,
|
|
||||||
struct fpi_frame *second_frame,
|
|
||||||
unsigned int *min_error)
|
|
||||||
{
|
|
||||||
int dx, dy;
|
|
||||||
unsigned int err;
|
|
||||||
*min_error = 255 * ctx->frame_height * ctx->frame_width;
|
|
||||||
|
|
||||||
/* Seeking in horizontal and vertical dimensions,
|
|
||||||
* for horizontal dimension we'll check only 8 pixels
|
|
||||||
* in both directions. For vertical direction diff is
|
|
||||||
* rarely less than 2, so start with it.
|
|
||||||
*/
|
|
||||||
for (dy = 2; dy < ctx->frame_height; dy++) {
|
|
||||||
for (dx = -8; dx < 8; dx++) {
|
|
||||||
err = calc_error(ctx, first_frame, second_frame,
|
|
||||||
dx, dy);
|
|
||||||
if (err < *min_error) {
|
|
||||||
*min_error = err;
|
|
||||||
second_frame->delta_x = -dx;
|
|
||||||
second_frame->delta_y = dy;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned int do_movement_estimation(struct fpi_frame_asmbl_ctx *ctx,
|
|
||||||
GSList *stripes, size_t num_stripes,
|
|
||||||
gboolean reverse)
|
|
||||||
{
|
|
||||||
GSList *list_entry = stripes;
|
|
||||||
GTimer *timer;
|
|
||||||
int frame = 1;
|
|
||||||
struct fpi_frame *prev_stripe = list_entry->data;
|
|
||||||
unsigned int min_error;
|
|
||||||
/* Max error is width * height * 255, for AES2501 which has the largest
|
|
||||||
* sensor its 192*16*255 = 783360. So for 32bit value it's ~5482 frame before
|
|
||||||
* we might get int overflow. Use 64bit value here to prevent integer overflow
|
|
||||||
*/
|
|
||||||
unsigned long long total_error = 0;
|
|
||||||
|
|
||||||
list_entry = g_slist_next(list_entry);
|
|
||||||
|
|
||||||
timer = g_timer_new();
|
|
||||||
do {
|
|
||||||
struct fpi_frame *cur_stripe = list_entry->data;
|
|
||||||
|
|
||||||
if (reverse) {
|
|
||||||
find_overlap(ctx, prev_stripe, cur_stripe, &min_error);
|
|
||||||
cur_stripe->delta_y = -cur_stripe->delta_y;
|
|
||||||
cur_stripe->delta_x = -cur_stripe->delta_x;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
find_overlap(ctx, cur_stripe, prev_stripe, &min_error);
|
|
||||||
total_error += min_error;
|
|
||||||
|
|
||||||
frame++;
|
|
||||||
prev_stripe = cur_stripe;
|
|
||||||
list_entry = g_slist_next(list_entry);
|
|
||||||
|
|
||||||
} while (frame < num_stripes);
|
|
||||||
|
|
||||||
g_timer_stop(timer);
|
|
||||||
fp_dbg("calc delta completed in %f secs", g_timer_elapsed(timer, NULL));
|
|
||||||
g_timer_destroy(timer);
|
|
||||||
|
|
||||||
return total_error / num_stripes;
|
|
||||||
}
|
|
||||||
|
|
||||||
void fpi_do_movement_estimation(struct fpi_frame_asmbl_ctx *ctx,
|
|
||||||
GSList *stripes, size_t num_stripes)
|
|
||||||
{
|
|
||||||
int err, rev_err;
|
|
||||||
err = do_movement_estimation(ctx, stripes, num_stripes, FALSE);
|
|
||||||
rev_err = do_movement_estimation(ctx, stripes, num_stripes, TRUE);
|
|
||||||
fp_dbg("errors: %d rev: %d", err, rev_err);
|
|
||||||
if (err < rev_err) {
|
|
||||||
do_movement_estimation(ctx, stripes, num_stripes, FALSE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void aes_blit_stripe(struct fpi_frame_asmbl_ctx *ctx,
|
|
||||||
struct fp_img *img,
|
|
||||||
struct fpi_frame *stripe,
|
|
||||||
int x, int y)
|
|
||||||
{
|
|
||||||
unsigned int ix, iy;
|
|
||||||
unsigned int fx, fy;
|
|
||||||
unsigned int width, height;
|
|
||||||
|
|
||||||
/* Find intersection */
|
|
||||||
if (x < 0) {
|
|
||||||
width = ctx->frame_width + x;
|
|
||||||
ix = 0;
|
|
||||||
fx = -x;
|
|
||||||
} else {
|
|
||||||
ix = x;
|
|
||||||
fx = 0;
|
|
||||||
width = ctx->frame_width;
|
|
||||||
}
|
|
||||||
if ((ix + width) > img->width)
|
|
||||||
width = img->width - ix;
|
|
||||||
|
|
||||||
if (y < 0) {
|
|
||||||
iy = 0;
|
|
||||||
fy = -y;
|
|
||||||
height = ctx->frame_height + y;
|
|
||||||
} else {
|
|
||||||
iy = y;
|
|
||||||
fy = 0;
|
|
||||||
height = ctx->frame_height;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fx > ctx->frame_width)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (fy > ctx->frame_height)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (ix > img->width)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (iy > img->height)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if ((iy + height) > img->height)
|
|
||||||
height = img->height - iy;
|
|
||||||
|
|
||||||
for (; fy < height; fy++, iy++) {
|
|
||||||
if (x < 0) {
|
|
||||||
ix = 0;
|
|
||||||
fx = -x;
|
|
||||||
} else {
|
|
||||||
ix = x;
|
|
||||||
fx = 0;
|
|
||||||
}
|
|
||||||
for (; fx < width; fx++, ix++) {
|
|
||||||
img->data[ix + (iy * img->width)] = ctx->get_pixel(ctx, stripe, fx, fy);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct fp_img *fpi_assemble_frames(struct fpi_frame_asmbl_ctx *ctx,
|
|
||||||
GSList *stripes, size_t stripes_len)
|
|
||||||
{
|
|
||||||
GSList *stripe;
|
|
||||||
struct fp_img *img;
|
|
||||||
int height = 0;
|
|
||||||
int i, y, x;
|
|
||||||
gboolean reverse = FALSE;
|
|
||||||
struct fpi_frame *fpi_frame;
|
|
||||||
|
|
||||||
BUG_ON(stripes_len == 0);
|
|
||||||
BUG_ON(ctx->image_width < ctx->frame_width);
|
|
||||||
|
|
||||||
/* Calculate height */
|
|
||||||
i = 0;
|
|
||||||
stripe = stripes;
|
|
||||||
|
|
||||||
/* No offset for 1st image */
|
|
||||||
fpi_frame = stripe->data;
|
|
||||||
fpi_frame->delta_x = 0;
|
|
||||||
fpi_frame->delta_y = 0;
|
|
||||||
do {
|
|
||||||
fpi_frame = stripe->data;
|
|
||||||
|
|
||||||
height += fpi_frame->delta_y;
|
|
||||||
i++;
|
|
||||||
stripe = g_slist_next(stripe);
|
|
||||||
} while (i < stripes_len);
|
|
||||||
|
|
||||||
fp_dbg("height is %d", height);
|
|
||||||
|
|
||||||
if (height < 0) {
|
|
||||||
reverse = TRUE;
|
|
||||||
height = -height;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* For last frame */
|
|
||||||
height += ctx->frame_height;
|
|
||||||
|
|
||||||
/* Create buffer big enough for max image */
|
|
||||||
img = fpi_img_new(ctx->image_width * height);
|
|
||||||
img->flags = FP_IMG_COLORS_INVERTED;
|
|
||||||
img->flags |= reverse ? 0 : FP_IMG_H_FLIPPED | FP_IMG_V_FLIPPED;
|
|
||||||
img->width = ctx->image_width;
|
|
||||||
img->height = height;
|
|
||||||
|
|
||||||
/* Assemble stripes */
|
|
||||||
i = 0;
|
|
||||||
stripe = stripes;
|
|
||||||
y = reverse ? (height - ctx->frame_height) : 0;
|
|
||||||
x = (ctx->image_width - ctx->frame_width) / 2;
|
|
||||||
|
|
||||||
do {
|
|
||||||
fpi_frame = stripe->data;
|
|
||||||
|
|
||||||
if(reverse) {
|
|
||||||
y += fpi_frame->delta_y;
|
|
||||||
x += fpi_frame->delta_x;
|
|
||||||
}
|
|
||||||
|
|
||||||
aes_blit_stripe(ctx, img, fpi_frame, x, y);
|
|
||||||
|
|
||||||
if(!reverse) {
|
|
||||||
y += fpi_frame->delta_y;
|
|
||||||
x += fpi_frame->delta_x;
|
|
||||||
}
|
|
||||||
|
|
||||||
stripe = g_slist_next(stripe);
|
|
||||||
i++;
|
|
||||||
} while (i < stripes_len);
|
|
||||||
|
|
||||||
return img;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cmpint(const void *p1, const void *p2, gpointer data)
|
|
||||||
{
|
|
||||||
int a = *((int *)p1);
|
|
||||||
int b = *((int *)p2);
|
|
||||||
if (a < b)
|
|
||||||
return -1;
|
|
||||||
else if (a == b)
|
|
||||||
return 0;
|
|
||||||
else
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void median_filter(int *data, int size, int filtersize)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
int *result = (int *)g_malloc0(size*sizeof(int));
|
|
||||||
int *sortbuf = (int *)g_malloc0(filtersize*sizeof(int));
|
|
||||||
for (i = 0; i < size; i++) {
|
|
||||||
int i1 = i - (filtersize-1)/2;
|
|
||||||
int i2 = i + (filtersize-1)/2;
|
|
||||||
if (i1 < 0)
|
|
||||||
i1 = 0;
|
|
||||||
if (i2 >= size)
|
|
||||||
i2 = size-1;
|
|
||||||
g_memmove(sortbuf, data+i1, (i2-i1+1)*sizeof(int));
|
|
||||||
g_qsort_with_data(sortbuf, i2-i1+1, sizeof(int), cmpint, NULL);
|
|
||||||
result[i] = sortbuf[(i2-i1+1)/2];
|
|
||||||
}
|
|
||||||
memmove(data, result, size*sizeof(int));
|
|
||||||
g_free(result);
|
|
||||||
g_free(sortbuf);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void interpolate_lines(struct fpi_line_asmbl_ctx *ctx,
|
|
||||||
GSList *line1, float y1, GSList *line2,
|
|
||||||
float y2, unsigned char *output, float yi, int size)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
unsigned char p1, p2;
|
|
||||||
|
|
||||||
if (!line1 || !line2)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (i = 0; i < size; i++) {
|
|
||||||
p1 = ctx->get_pixel(ctx, line1, i);
|
|
||||||
p2 = ctx->get_pixel(ctx, line2, i);
|
|
||||||
output[i] = (float)p1
|
|
||||||
+ (yi - y1)/(y2 - y1)*(p2 - p1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int min(int a, int b) {return (a < b) ? a : b; }
|
|
||||||
|
|
||||||
/* Rescale image to account for variable swiping speed */
|
|
||||||
struct fp_img *fpi_assemble_lines(struct fpi_line_asmbl_ctx *ctx,
|
|
||||||
GSList *lines, size_t lines_len)
|
|
||||||
{
|
|
||||||
/* Number of output lines per distance between two scanners */
|
|
||||||
int i;
|
|
||||||
GSList *row1, *row2;
|
|
||||||
float y = 0.0;
|
|
||||||
int line_ind = 0;
|
|
||||||
int *offsets = (int *)g_malloc0((lines_len / 2) * sizeof(int));
|
|
||||||
unsigned char *output = g_malloc0(ctx->line_width * ctx->max_height);
|
|
||||||
struct fp_img *img;
|
|
||||||
|
|
||||||
g_return_val_if_fail (lines != NULL, NULL);
|
|
||||||
g_return_val_if_fail (lines_len > 0, NULL);
|
|
||||||
|
|
||||||
fp_dbg("%"G_GINT64_FORMAT, g_get_real_time());
|
|
||||||
|
|
||||||
row1 = lines;
|
|
||||||
for (i = 0; (i < lines_len - 1) && row1; i += 2) {
|
|
||||||
int bestmatch = i;
|
|
||||||
int bestdiff = 0;
|
|
||||||
int j, firstrow, lastrow;
|
|
||||||
|
|
||||||
firstrow = i + 1;
|
|
||||||
lastrow = min(i + ctx->max_search_offset, lines_len - 1);
|
|
||||||
|
|
||||||
row2 = g_slist_next(row1);
|
|
||||||
for (j = firstrow; j <= lastrow; j++) {
|
|
||||||
int diff = ctx->get_deviation(ctx,
|
|
||||||
row1,
|
|
||||||
row2);
|
|
||||||
if ((j == firstrow) || (diff < bestdiff)) {
|
|
||||||
bestdiff = diff;
|
|
||||||
bestmatch = j;
|
|
||||||
}
|
|
||||||
row2 = g_slist_next(row2);
|
|
||||||
}
|
|
||||||
offsets[i / 2] = bestmatch - i;
|
|
||||||
fp_dbg("%d", offsets[i / 2]);
|
|
||||||
row1 = g_slist_next(row1);
|
|
||||||
if (row1)
|
|
||||||
row1 = g_slist_next(row1);
|
|
||||||
}
|
|
||||||
|
|
||||||
median_filter(offsets, (lines_len / 2) - 1, ctx->median_filter_size);
|
|
||||||
|
|
||||||
fp_dbg("offsets_filtered: %"G_GINT64_FORMAT, g_get_real_time());
|
|
||||||
for (i = 0; i <= (lines_len / 2) - 1; i++)
|
|
||||||
fp_dbg("%d", offsets[i]);
|
|
||||||
row1 = lines;
|
|
||||||
for (i = 0; i < lines_len - 1; i++, row1 = g_slist_next(row1)) {
|
|
||||||
int offset = offsets[i/2];
|
|
||||||
if (offset > 0) {
|
|
||||||
float ynext = y + (float)ctx->resolution / offset;
|
|
||||||
while (line_ind < ynext) {
|
|
||||||
if (line_ind > ctx->max_height - 1)
|
|
||||||
goto out;
|
|
||||||
interpolate_lines(ctx,
|
|
||||||
row1, y,
|
|
||||||
g_slist_next(row1),
|
|
||||||
ynext,
|
|
||||||
output + line_ind * ctx->line_width,
|
|
||||||
line_ind,
|
|
||||||
ctx->line_width);
|
|
||||||
line_ind++;
|
|
||||||
}
|
|
||||||
y = ynext;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
out:
|
|
||||||
img = fpi_img_new(ctx->line_width * line_ind);
|
|
||||||
img->height = line_ind;
|
|
||||||
img->width = ctx->line_width;
|
|
||||||
img->flags = FP_IMG_V_FLIPPED;
|
|
||||||
g_memmove(img->data, output, ctx->line_width * line_ind);
|
|
||||||
g_free(offsets);
|
|
||||||
g_free(output);
|
|
||||||
return img;
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
/*
|
|
||||||
* Image assembling routines
|
|
||||||
* Shared functions between libfprint Authentec drivers
|
|
||||||
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
|
|
||||||
* Copyright (C) 2015 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
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __ASSEMBLING_H__
|
|
||||||
#define __ASSEMBLING_H__
|
|
||||||
|
|
||||||
#include <fprint.h>
|
|
||||||
|
|
||||||
struct fpi_frame {
|
|
||||||
int delta_x;
|
|
||||||
int delta_y;
|
|
||||||
unsigned char data[0];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct fpi_frame_asmbl_ctx {
|
|
||||||
unsigned frame_width;
|
|
||||||
unsigned frame_height;
|
|
||||||
unsigned image_width;
|
|
||||||
unsigned char (*get_pixel)(struct fpi_frame_asmbl_ctx *ctx,
|
|
||||||
struct fpi_frame *frame,
|
|
||||||
unsigned x,
|
|
||||||
unsigned y);
|
|
||||||
};
|
|
||||||
|
|
||||||
void fpi_do_movement_estimation(struct fpi_frame_asmbl_ctx *ctx,
|
|
||||||
GSList *stripes, size_t stripes_len);
|
|
||||||
|
|
||||||
struct fp_img *fpi_assemble_frames(struct fpi_frame_asmbl_ctx *ctx,
|
|
||||||
GSList *stripes, size_t stripes_len);
|
|
||||||
|
|
||||||
struct fpi_line_asmbl_ctx {
|
|
||||||
unsigned line_width;
|
|
||||||
unsigned max_height;
|
|
||||||
unsigned resolution;
|
|
||||||
unsigned median_filter_size;
|
|
||||||
unsigned max_search_offset;
|
|
||||||
int (*get_deviation)(struct fpi_line_asmbl_ctx *ctx,
|
|
||||||
GSList *line1, GSList *line2);
|
|
||||||
unsigned char (*get_pixel)(struct fpi_line_asmbl_ctx *ctx,
|
|
||||||
GSList *line,
|
|
||||||
unsigned x);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct fp_img *fpi_assemble_lines(struct fpi_line_asmbl_ctx *ctx,
|
|
||||||
GSList *lines, size_t lines_len);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,629 +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 "fp_internal.h"
|
|
||||||
|
|
||||||
#include <config.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <glib.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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_async_dev_open:
|
|
||||||
* @ddev:
|
|
||||||
* @callback:
|
|
||||||
* @user_data
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_async_dev_open(struct fp_dscv_dev *ddev, fp_dev_open_cb callback,
|
|
||||||
void *user_data)
|
|
||||||
{
|
|
||||||
struct fp_driver *drv;
|
|
||||||
struct fp_dev *dev;
|
|
||||||
libusb_device_handle *udevh;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
g_return_val_if_fail(ddev != NULL, -ENODEV);
|
|
||||||
|
|
||||||
drv = ddev->drv;
|
|
||||||
|
|
||||||
G_DEBUG_HERE();
|
|
||||||
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 = callback;
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
G_DEBUG_HERE();
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_async_dev_close:
|
|
||||||
* @dev:
|
|
||||||
* @callback:
|
|
||||||
* @user_data
|
|
||||||
*/
|
|
||||||
API_EXPORTED void fp_async_dev_close(struct fp_dev *dev,
|
|
||||||
fp_operation_stop_cb callback, void *user_data)
|
|
||||||
{
|
|
||||||
struct fp_driver *drv;
|
|
||||||
|
|
||||||
g_return_if_fail (dev != NULL);
|
|
||||||
|
|
||||||
drv = dev->drv;
|
|
||||||
|
|
||||||
g_return_if_fail (drv->close != NULL);
|
|
||||||
|
|
||||||
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;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_async_enroll_start:
|
|
||||||
* @dev:
|
|
||||||
* @callback:
|
|
||||||
* @user_data:
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_async_enroll_start(struct fp_dev *dev,
|
|
||||||
fp_enroll_stage_cb callback, void *user_data)
|
|
||||||
{
|
|
||||||
struct fp_driver *drv;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
g_return_val_if_fail(dev != NULL, -ENODEV);
|
|
||||||
|
|
||||||
drv = dev->drv;
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
G_DEBUG_HERE();
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_async_enroll_stop:
|
|
||||||
* @dev:
|
|
||||||
* @callback:
|
|
||||||
* @user_data:
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_async_enroll_stop(struct fp_dev *dev,
|
|
||||||
fp_operation_stop_cb callback, void *user_data)
|
|
||||||
{
|
|
||||||
struct fp_driver *drv;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
g_return_val_if_fail(dev != NULL, -ENODEV);
|
|
||||||
|
|
||||||
drv = dev->drv;
|
|
||||||
|
|
||||||
G_DEBUG_HERE();
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_async_verify_start:
|
|
||||||
* @dev:
|
|
||||||
* @data:
|
|
||||||
* @callback:
|
|
||||||
* @user_data:
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_async_verify_start(struct fp_dev *dev,
|
|
||||||
struct fp_print_data *data, fp_img_operation_cb callback, void *user_data)
|
|
||||||
{
|
|
||||||
struct fp_driver *drv;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
g_return_val_if_fail(dev != NULL, -ENODEV);
|
|
||||||
|
|
||||||
drv = dev->drv;
|
|
||||||
|
|
||||||
G_DEBUG_HERE();
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
G_DEBUG_HERE();
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
G_DEBUG_HERE();
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_async_verify_stop:
|
|
||||||
* @dev:
|
|
||||||
* @callback:
|
|
||||||
* @user_data:
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_async_verify_stop(struct fp_dev *dev,
|
|
||||||
fp_operation_stop_cb callback, void *user_data)
|
|
||||||
{
|
|
||||||
struct fp_driver *drv;
|
|
||||||
gboolean iterating = (dev->state == DEV_STATE_VERIFYING);
|
|
||||||
int r;
|
|
||||||
|
|
||||||
g_return_val_if_fail(dev != NULL, -ENODEV);
|
|
||||||
|
|
||||||
drv = dev->drv;
|
|
||||||
|
|
||||||
G_DEBUG_HERE();
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_async_identify_start:
|
|
||||||
* @dev:
|
|
||||||
* @gallery:
|
|
||||||
* @callback:
|
|
||||||
* @user_data:
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
*/
|
|
||||||
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;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
g_return_val_if_fail(dev != NULL, -ENODEV);
|
|
||||||
|
|
||||||
drv = dev->drv;
|
|
||||||
|
|
||||||
G_DEBUG_HERE();
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_async_identify_stop:
|
|
||||||
* @dev:
|
|
||||||
* @callback:
|
|
||||||
* @user_data:
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_async_identify_stop(struct fp_dev *dev,
|
|
||||||
fp_operation_stop_cb callback, void *user_data)
|
|
||||||
{
|
|
||||||
struct fp_driver *drv;
|
|
||||||
gboolean iterating = (dev->state == DEV_STATE_IDENTIFYING);
|
|
||||||
int r;
|
|
||||||
|
|
||||||
g_return_val_if_fail(dev != NULL, -ENODEV);
|
|
||||||
|
|
||||||
drv = dev->drv;
|
|
||||||
|
|
||||||
G_DEBUG_HERE();
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
G_DEBUG_HERE();
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_async_capture_start:
|
|
||||||
* @dev:
|
|
||||||
* @unconditional:
|
|
||||||
* @callback:
|
|
||||||
* @user_data:
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_async_capture_start(struct fp_dev *dev, int unconditional,
|
|
||||||
fp_img_operation_cb callback, void *user_data)
|
|
||||||
{
|
|
||||||
struct fp_driver *drv;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
g_return_val_if_fail(dev != NULL, -ENODEV);
|
|
||||||
|
|
||||||
drv = dev->drv;
|
|
||||||
|
|
||||||
G_DEBUG_HERE();
|
|
||||||
if (!drv->capture_start)
|
|
||||||
return -ENOTSUP;
|
|
||||||
|
|
||||||
dev->state = DEV_STATE_CAPTURE_STARTING;
|
|
||||||
dev->capture_cb = callback;
|
|
||||||
dev->capture_cb_data = user_data;
|
|
||||||
dev->unconditional_capture = unconditional;
|
|
||||||
|
|
||||||
r = drv->capture_start(dev);
|
|
||||||
if (r < 0) {
|
|
||||||
dev->capture_cb = NULL;
|
|
||||||
dev->state = DEV_STATE_ERROR;
|
|
||||||
fp_err("failed to start verification, error %d", r);
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Drivers call this when capture has started */
|
|
||||||
void fpi_drvcb_capture_started(struct fp_dev *dev, int status)
|
|
||||||
{
|
|
||||||
G_DEBUG_HERE();
|
|
||||||
BUG_ON(dev->state != DEV_STATE_CAPTURE_STARTING);
|
|
||||||
if (status) {
|
|
||||||
if (status > 0) {
|
|
||||||
status = -status;
|
|
||||||
fp_dbg("adjusted to %d", status);
|
|
||||||
}
|
|
||||||
dev->state = DEV_STATE_ERROR;
|
|
||||||
if (dev->capture_cb)
|
|
||||||
dev->capture_cb(dev, status, NULL, dev->capture_cb_data);
|
|
||||||
} else {
|
|
||||||
dev->state = DEV_STATE_CAPTURING;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Drivers call this to report a capture result (which might mark completion) */
|
|
||||||
void fpi_drvcb_report_capture_result(struct fp_dev *dev, int result,
|
|
||||||
struct fp_img *img)
|
|
||||||
{
|
|
||||||
fp_dbg("result %d", result);
|
|
||||||
BUG_ON(dev->state != DEV_STATE_CAPTURING);
|
|
||||||
if (result < 0 || result == FP_CAPTURE_COMPLETE)
|
|
||||||
dev->state = DEV_STATE_CAPTURE_DONE;
|
|
||||||
|
|
||||||
if (dev->capture_cb)
|
|
||||||
dev->capture_cb(dev, result, img, dev->capture_cb_data);
|
|
||||||
else
|
|
||||||
fp_dbg("ignoring capture result as no callback is subscribed");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Drivers call this when capture has stopped */
|
|
||||||
void fpi_drvcb_capture_stopped(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
G_DEBUG_HERE();
|
|
||||||
BUG_ON(dev->state != DEV_STATE_CAPTURE_STOPPING);
|
|
||||||
dev->state = DEV_STATE_INITIALIZED;
|
|
||||||
if (dev->capture_stop_cb)
|
|
||||||
dev->capture_stop_cb(dev, dev->capture_stop_cb_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_async_capture_stop:
|
|
||||||
* @dev:
|
|
||||||
* @callback:
|
|
||||||
* @user_data:
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_async_capture_stop(struct fp_dev *dev,
|
|
||||||
fp_operation_stop_cb callback, void *user_data)
|
|
||||||
{
|
|
||||||
struct fp_driver *drv;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
g_return_val_if_fail(dev != NULL, -ENODEV);
|
|
||||||
|
|
||||||
drv = dev->drv;
|
|
||||||
|
|
||||||
G_DEBUG_HERE();
|
|
||||||
BUG_ON(dev->state != DEV_STATE_ERROR
|
|
||||||
&& dev->state != DEV_STATE_CAPTURING
|
|
||||||
&& dev->state != DEV_STATE_CAPTURE_DONE);
|
|
||||||
|
|
||||||
dev->capture_cb = NULL;
|
|
||||||
dev->capture_stop_cb = callback;
|
|
||||||
dev->capture_stop_cb_data = user_data;
|
|
||||||
dev->state = DEV_STATE_CAPTURE_STOPPING;
|
|
||||||
|
|
||||||
if (!drv->capture_start)
|
|
||||||
return -ENOTSUP;
|
|
||||||
if (!drv->capture_stop) {
|
|
||||||
dev->state = DEV_STATE_INITIALIZED;
|
|
||||||
fpi_drvcb_capture_stopped(dev);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = drv->capture_stop(dev);
|
|
||||||
if (r < 0) {
|
|
||||||
fp_err("failed to stop verification");
|
|
||||||
dev->capture_stop_cb = NULL;
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
794
libfprint/core.c
@@ -1,794 +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"
|
|
||||||
|
|
||||||
libusb_context *fpi_usb_ctx = NULL;
|
|
||||||
GSList *opened_devices = NULL;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SECTION:discovery
|
|
||||||
* @title: 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SECTION:drv
|
|
||||||
* @title: 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:dev
|
|
||||||
* @title: Devices operations
|
|
||||||
*
|
|
||||||
* In order to interact with fingerprint scanners, your software will
|
|
||||||
* interface primarily with libfprint's representation of devices, detailed
|
|
||||||
* on this page.
|
|
||||||
*
|
|
||||||
* # 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 in-between 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.
|
|
||||||
*
|
|
||||||
* # 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static GSList *registered_drivers = NULL;
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "drivers_arrays.h"
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_discover_devs:
|
|
||||||
*
|
|
||||||
* 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)
|
|
||||||
{
|
|
||||||
GPtrArray *tmparray;
|
|
||||||
libusb_device *udev;
|
|
||||||
libusb_device **devs;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
tmparray = g_ptr_array_new ();
|
|
||||||
|
|
||||||
/* Check each device against each driver, temporarily storing successfully
|
|
||||||
* discovered devices in a GPtrArray. */
|
|
||||||
while ((udev = devs[i++]) != NULL) {
|
|
||||||
struct fp_dscv_dev *ddev = discover_dev(udev);
|
|
||||||
if (!ddev)
|
|
||||||
continue;
|
|
||||||
/* discover_dev() doesn't hold a reference to the udev,
|
|
||||||
* so increase the reference for ddev to hold this ref */
|
|
||||||
libusb_ref_device(udev);
|
|
||||||
g_ptr_array_add (tmparray, (gpointer) ddev);
|
|
||||||
}
|
|
||||||
libusb_free_device_list(devs, 1);
|
|
||||||
|
|
||||||
/* Convert our temporary array into a standard NULL-terminated pointer
|
|
||||||
* array. */
|
|
||||||
g_ptr_array_add (tmparray, NULL);
|
|
||||||
return (struct fp_dscv_dev **) g_ptr_array_free (tmparray, FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_dscv_devs_free:
|
|
||||||
* @devs: the list of discovered devices. If %NULL, function simply
|
|
||||||
* returns.
|
|
||||||
*
|
|
||||||
* 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 <emphasis role="strong">before</emphasis> freeing the list.
|
|
||||||
*/
|
|
||||||
API_EXPORTED void fp_dscv_devs_free(struct fp_dscv_dev **devs)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
if (!devs)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (i = 0; devs[i]; i++) {
|
|
||||||
libusb_unref_device(devs[i]->udev);
|
|
||||||
g_free(devs[i]);
|
|
||||||
}
|
|
||||||
g_free(devs);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_dscv_dev_get_driver:
|
|
||||||
* @dev: the discovered device
|
|
||||||
*
|
|
||||||
* Gets the #fp_driver for a 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_dscv_dev_get_driver_id:
|
|
||||||
* @dev: a discovered fingerprint device
|
|
||||||
*
|
|
||||||
* Returns: the ID for the underlying driver for that device
|
|
||||||
*/
|
|
||||||
API_EXPORTED uint16_t fp_dscv_dev_get_driver_id(struct fp_dscv_dev *dev)
|
|
||||||
{
|
|
||||||
return fp_driver_get_driver_id(fp_dscv_dev_get_driver(dev));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_dscv_dev_get_devtype:
|
|
||||||
* @dev: the discovered device
|
|
||||||
*
|
|
||||||
* Gets the [devtype](advanced-topics.html#device-types) for a 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_dscv_dev_supports_print_data:
|
|
||||||
* @dev: the discovered device
|
|
||||||
* @print: the print for compatibility checking
|
|
||||||
*
|
|
||||||
* Determines if a specific #fp_print_data stored print appears to be
|
|
||||||
* compatible with a discovered device.
|
|
||||||
*
|
|
||||||
* 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 *print)
|
|
||||||
{
|
|
||||||
return fpi_print_data_compatible(dev->drv->id, dev->devtype,
|
|
||||||
fpi_driver_get_data_type(dev->drv), print->driver_id, print->devtype,
|
|
||||||
print->type);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_dscv_dev_supports_dscv_print:
|
|
||||||
* @dev: the discovered device
|
|
||||||
* @print: the discovered print for compatibility checking
|
|
||||||
*
|
|
||||||
* Determines if a specific #fp_dscv_print discovered print appears to be
|
|
||||||
* compatible with a discovered device.
|
|
||||||
*
|
|
||||||
* Returns: 1 if the print is compatible with the device, 0 otherwise
|
|
||||||
*
|
|
||||||
* Deprecated: Do not use.
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_dscv_dev_supports_dscv_print(struct fp_dscv_dev *dev,
|
|
||||||
struct fp_dscv_print *print)
|
|
||||||
{
|
|
||||||
return fpi_print_data_compatible(dev->drv->id, dev->devtype, 0,
|
|
||||||
print->driver_id, print->devtype, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_dscv_dev_for_print_data:
|
|
||||||
* @devs: a list of discovered devices
|
|
||||||
* @print: the print under inspection
|
|
||||||
*
|
|
||||||
* Searches a list of discovered devices for a device that appears to be
|
|
||||||
* compatible with a #fp_print_data stored print.
|
|
||||||
*
|
|
||||||
* Returns: the first discovered device that appears to support the print, or
|
|
||||||
* %NULL if no apparently compatible devices could be found
|
|
||||||
*
|
|
||||||
* Deprecated: Do not use.
|
|
||||||
*/
|
|
||||||
API_EXPORTED struct fp_dscv_dev *fp_dscv_dev_for_print_data(struct fp_dscv_dev **devs,
|
|
||||||
struct fp_print_data *print)
|
|
||||||
{
|
|
||||||
struct fp_dscv_dev *ddev;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; (ddev = devs[i]); i++)
|
|
||||||
if (fp_dscv_dev_supports_print_data(ddev, print))
|
|
||||||
return ddev;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_dscv_dev_for_dscv_print:
|
|
||||||
* @devs: a list of discovered devices
|
|
||||||
* @print: the print under inspection
|
|
||||||
*
|
|
||||||
* Searches a list of discovered devices for a device that appears to be
|
|
||||||
* compatible with a #fp_dscv_print discovered print.
|
|
||||||
*
|
|
||||||
* Returns: the first discovered device that appears to support the print, or
|
|
||||||
* %NULL if no apparently compatible devices could be found
|
|
||||||
*
|
|
||||||
* Deprecated: Do not use.
|
|
||||||
*/
|
|
||||||
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++) {
|
|
||||||
#pragma GCC diagnostic push
|
|
||||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
|
||||||
if (fp_dscv_dev_supports_dscv_print(ddev, print))
|
|
||||||
return ddev;
|
|
||||||
#pragma GCC diagnostic pop
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_dev_get_driver:
|
|
||||||
* @dev: the device
|
|
||||||
*
|
|
||||||
* Get the #fp_driver for a fingerprint device.
|
|
||||||
*
|
|
||||||
* Returns: the driver controlling the device
|
|
||||||
*/
|
|
||||||
API_EXPORTED struct fp_driver *fp_dev_get_driver(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
return dev->drv;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_dev_get_nr_enroll_stages:
|
|
||||||
* @dev: the device
|
|
||||||
*
|
|
||||||
* Gets the number of [enroll stages](intro.html#enrollment) required to enroll a
|
|
||||||
* fingerprint with 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_dev_get_devtype:
|
|
||||||
* @dev: the device
|
|
||||||
*
|
|
||||||
* Gets the [devtype](advanced-topics.html#device-types) for a device.
|
|
||||||
*
|
|
||||||
* Returns: the devtype
|
|
||||||
*/
|
|
||||||
API_EXPORTED uint32_t fp_dev_get_devtype(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
return dev->devtype;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_dev_supports_print_data:
|
|
||||||
* @dev: the device
|
|
||||||
* @data: the stored print
|
|
||||||
*
|
|
||||||
* Determines if a stored print is compatible with a certain device.
|
|
||||||
*
|
|
||||||
* 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_dev_supports_dscv_print:
|
|
||||||
* @dev: the device
|
|
||||||
* @print: the discovered print
|
|
||||||
*
|
|
||||||
* Determines if a #fp_dscv_print discovered print appears to be compatible
|
|
||||||
* with a certain device.
|
|
||||||
*
|
|
||||||
* Returns: 1 if the print is compatible with the device, 0 if not
|
|
||||||
*
|
|
||||||
* Deprecated: Do not use.
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_dev_supports_dscv_print(struct fp_dev *dev,
|
|
||||||
struct fp_dscv_print *print)
|
|
||||||
{
|
|
||||||
return fpi_print_data_compatible(dev->drv->id, dev->devtype,
|
|
||||||
0, print->driver_id, print->devtype, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
libusb_device_handle *
|
|
||||||
fpi_dev_get_usb_dev(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
return dev->udev;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *
|
|
||||||
fpi_dev_get_user_data (struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
return dev->priv;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
fpi_dev_set_user_data (struct fp_dev *dev,
|
|
||||||
void *user_data)
|
|
||||||
{
|
|
||||||
dev->priv = user_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
fpi_dev_get_nr_enroll_stages(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
return dev->nr_enroll_stages;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
fpi_dev_set_nr_enroll_stages(struct fp_dev *dev,
|
|
||||||
int nr_enroll_stages)
|
|
||||||
{
|
|
||||||
dev->nr_enroll_stages = nr_enroll_stages;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct fp_print_data *
|
|
||||||
fpi_dev_get_verify_data(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
return dev->verify_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum fp_dev_state
|
|
||||||
fpi_dev_get_dev_state(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
return dev->state;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_driver_get_name:
|
|
||||||
* @drv: the driver
|
|
||||||
*
|
|
||||||
* Retrieves the name of the driver. For example: "upekts"
|
|
||||||
*
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_driver_get_full_name:
|
|
||||||
* @drv: the driver
|
|
||||||
*
|
|
||||||
* Retrieves a descriptive name of the driver. For example: "UPEK TouchStrip"
|
|
||||||
*
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_driver_get_driver_id:
|
|
||||||
* @drv: the driver
|
|
||||||
*
|
|
||||||
* Retrieves the driver ID code for a driver.
|
|
||||||
*
|
|
||||||
* Returns: the driver ID
|
|
||||||
*/
|
|
||||||
API_EXPORTED uint16_t fp_driver_get_driver_id(struct fp_driver *drv)
|
|
||||||
{
|
|
||||||
return drv->id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_driver_get_scan_type:
|
|
||||||
* @drv: the driver
|
|
||||||
*
|
|
||||||
* Retrieves the scan type for the devices associated with 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_dev_supports_imaging:
|
|
||||||
* @dev: the fingerprint device
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* 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->capture_start != NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_dev_supports_identification:
|
|
||||||
* @dev: the fingerprint device
|
|
||||||
*
|
|
||||||
* Determines if a device is capable of [identification](intro.html#identification)
|
|
||||||
* through fp_identify_finger() and similar. Not all devices support this
|
|
||||||
* functionality.
|
|
||||||
*
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_dev_get_img_width:
|
|
||||||
* @dev: the fingerprint device
|
|
||||||
*
|
|
||||||
* Gets the expected width of images that will be captured from the device.
|
|
||||||
* This function will return -1 for devices that are not
|
|
||||||
* [imaging devices](libfprint-Devices-operations.html#imaging). If the width of images from this device
|
|
||||||
* can vary, 0 will be returned.
|
|
||||||
*
|
|
||||||
* 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_dev_get_img_height:
|
|
||||||
* @dev: the fingerprint device
|
|
||||||
*
|
|
||||||
* Gets the expected height of images that will be captured from the device.
|
|
||||||
* This function will return -1 for devices that are not
|
|
||||||
* [imaging devices](libfprint-Devices-operations.html#imaging). If the height of images from this device
|
|
||||||
* can vary, 0 will be returned.
|
|
||||||
*
|
|
||||||
* 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_set_debug:
|
|
||||||
* @level: the verbosity level
|
|
||||||
*
|
|
||||||
* This call does nothing, see fp_init() for details.
|
|
||||||
*/
|
|
||||||
API_EXPORTED void fp_set_debug(int level)
|
|
||||||
{
|
|
||||||
/* Nothing */
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_init:
|
|
||||||
*
|
|
||||||
* Initialise libfprint. This function must be called before you attempt to
|
|
||||||
* use the library in any way.
|
|
||||||
*
|
|
||||||
* To enable debug output of libfprint specifically, use GLib's `G_MESSAGES_DEBUG`
|
|
||||||
* environment variable as explained in [Running and debugging GLib Applications](https://developer.gnome.org/glib/stable/glib-running.html#G_MESSAGES_DEBUG).
|
|
||||||
*
|
|
||||||
* The log domains used in libfprint are either `libfprint` or `libfprint-FP_COMPONENT`
|
|
||||||
* where `FP_COMPONENT` is defined in the source code for each driver, or component
|
|
||||||
* of the library. Starting with `all` and trimming down is advised.
|
|
||||||
*
|
|
||||||
* To enable debugging of libusb, for USB-based fingerprint reader drivers, use
|
|
||||||
* libusb's `LIBUSB_DEBUG` environment variable as explained in the
|
|
||||||
* [libusb-1.0 API Reference](http://libusb.sourceforge.net/api-1.0/#msglog).
|
|
||||||
*
|
|
||||||
* Example:
|
|
||||||
*
|
|
||||||
* ```
|
|
||||||
* LIBUSB_DEBUG=4 G_MESSAGES_DEBUG=all my-libfprint-application
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* Returns: 0 on success, non-zero on error.
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_init(void)
|
|
||||||
{
|
|
||||||
int r;
|
|
||||||
G_DEBUG_HERE();
|
|
||||||
|
|
||||||
r = libusb_init(&fpi_usb_ctx);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
register_drivers();
|
|
||||||
fpi_poll_init();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_exit:
|
|
||||||
*
|
|
||||||
* 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)
|
|
||||||
{
|
|
||||||
G_DEBUG_HERE();
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
846
libfprint/data.c
@@ -1,846 +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
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SECTION: print_data
|
|
||||||
* @title: Stored prints
|
|
||||||
*
|
|
||||||
* Stored prints are represented by a structure named #fp_print_data.
|
|
||||||
* 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 */
|
|
||||||
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];
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct fp_print_data *print_data_new(uint16_t driver_id,
|
|
||||||
uint32_t devtype, enum fp_print_data_type type)
|
|
||||||
{
|
|
||||||
struct fp_print_data *data = g_malloc0(sizeof(*data));
|
|
||||||
fp_dbg("driver=%02x devtype=%04x", driver_id, devtype);
|
|
||||||
data->driver_id = driver_id;
|
|
||||||
data->devtype = devtype;
|
|
||||||
data->type = type;
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
void fpi_print_data_item_free(struct fp_print_data_item *item)
|
|
||||||
{
|
|
||||||
g_free(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct fp_print_data_item *fpi_print_data_item_new(size_t length)
|
|
||||||
{
|
|
||||||
struct fp_print_data_item *item = g_malloc0(sizeof(*item) + length);
|
|
||||||
item->length = length;
|
|
||||||
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct fp_print_data *fpi_print_data_new(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
return print_data_new(dev->drv->id, dev->devtype,
|
|
||||||
fpi_driver_get_data_type(dev->drv));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_print_data_get_data:
|
|
||||||
* @data: the stored print
|
|
||||||
* @ret: output location for the data buffer. Must be freed with free()
|
|
||||||
* after use.
|
|
||||||
|
|
||||||
* 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().
|
|
||||||
*
|
|
||||||
* 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_fp2 *out_data;
|
|
||||||
struct fpi_print_data_item_fp2 *out_item;
|
|
||||||
struct fp_print_data_item *item;
|
|
||||||
size_t buflen = 0;
|
|
||||||
GSList *list_item;
|
|
||||||
unsigned char *buf;
|
|
||||||
|
|
||||||
G_DEBUG_HERE();
|
|
||||||
|
|
||||||
list_item = data->prints;
|
|
||||||
while (list_item) {
|
|
||||||
item = list_item->data;
|
|
||||||
buflen += sizeof(*out_item);
|
|
||||||
buflen += item->length;
|
|
||||||
list_item = g_slist_next(list_item);
|
|
||||||
}
|
|
||||||
|
|
||||||
buflen += sizeof(*out_data);
|
|
||||||
out_data = g_malloc(buflen);
|
|
||||||
|
|
||||||
*ret = (unsigned char *) out_data;
|
|
||||||
buf = out_data->data;
|
|
||||||
out_data->prefix[0] = 'F';
|
|
||||||
out_data->prefix[1] = 'P';
|
|
||||||
out_data->prefix[2] = '2';
|
|
||||||
out_data->driver_id = GUINT16_TO_LE(data->driver_id);
|
|
||||||
out_data->devtype = GUINT32_TO_LE(data->devtype);
|
|
||||||
out_data->data_type = data->type;
|
|
||||||
|
|
||||||
list_item = data->prints;
|
|
||||||
while (list_item) {
|
|
||||||
item = list_item->data;
|
|
||||||
out_item = (struct fpi_print_data_item_fp2 *)buf;
|
|
||||||
out_item->length = GUINT32_TO_LE(item->length);
|
|
||||||
/* FIXME: fp_print_data_item->data content is not endianess agnostic */
|
|
||||||
memcpy(out_item->data, item->data, item->length);
|
|
||||||
buf += sizeof(*out_item);
|
|
||||||
buf += item->length;
|
|
||||||
list_item = g_slist_next(list_item);
|
|
||||||
}
|
|
||||||
|
|
||||||
return buflen;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct fp_print_data *fpi_print_data_from_fp1_data(unsigned char *buf,
|
|
||||||
size_t buflen)
|
|
||||||
{
|
|
||||||
size_t print_data_len;
|
|
||||||
struct fp_print_data *data;
|
|
||||||
struct fp_print_data_item *item;
|
|
||||||
struct fpi_print_data_fp2 *raw = (struct fpi_print_data_fp2 *) buf;
|
|
||||||
|
|
||||||
print_data_len = buflen - sizeof(*raw);
|
|
||||||
data = print_data_new(GUINT16_FROM_LE(raw->driver_id),
|
|
||||||
GUINT32_FROM_LE(raw->devtype), raw->data_type);
|
|
||||||
item = fpi_print_data_item_new(print_data_len);
|
|
||||||
/* FIXME: fp_print_data->data content is not endianess agnostic */
|
|
||||||
memcpy(item->data, raw->data, print_data_len);
|
|
||||||
data->prints = g_slist_prepend(data->prints, item);
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct fp_print_data *fpi_print_data_from_fp2_data(unsigned char *buf,
|
|
||||||
size_t buflen)
|
|
||||||
{
|
|
||||||
size_t total_data_len, item_len;
|
|
||||||
struct fp_print_data *data;
|
|
||||||
struct fp_print_data_item *item;
|
|
||||||
struct fpi_print_data_fp2 *raw = (struct fpi_print_data_fp2 *) buf;
|
|
||||||
unsigned char *raw_buf;
|
|
||||||
struct fpi_print_data_item_fp2 *raw_item;
|
|
||||||
|
|
||||||
total_data_len = buflen - sizeof(*raw);
|
|
||||||
data = print_data_new(GUINT16_FROM_LE(raw->driver_id),
|
|
||||||
GUINT32_FROM_LE(raw->devtype), raw->data_type);
|
|
||||||
raw_buf = raw->data;
|
|
||||||
while (total_data_len) {
|
|
||||||
if (total_data_len < sizeof(*raw_item))
|
|
||||||
break;
|
|
||||||
total_data_len -= sizeof(*raw_item);
|
|
||||||
|
|
||||||
raw_item = (struct fpi_print_data_item_fp2 *)raw_buf;
|
|
||||||
item_len = GUINT32_FROM_LE(raw_item->length);
|
|
||||||
fp_dbg("item len %d, total_data_len %d", (int) item_len, (int) total_data_len);
|
|
||||||
if (total_data_len < item_len) {
|
|
||||||
fp_err("corrupted fingerprint data");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
total_data_len -= item_len;
|
|
||||||
|
|
||||||
item = fpi_print_data_item_new(item_len);
|
|
||||||
/* FIXME: fp_print_data->data content is not endianess agnostic */
|
|
||||||
memcpy(item->data, raw_item->data, item_len);
|
|
||||||
data->prints = g_slist_prepend(data->prints, item);
|
|
||||||
|
|
||||||
raw_buf += sizeof(*raw_item);
|
|
||||||
raw_buf += item_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (g_slist_length(data->prints) == 0) {
|
|
||||||
fp_print_data_free(data);
|
|
||||||
data = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_print_data_from_data:
|
|
||||||
* @buf: the data buffer
|
|
||||||
* @buflen: the length of the buffer
|
|
||||||
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* 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_fp2 *raw = (struct fpi_print_data_fp2 *) buf;
|
|
||||||
|
|
||||||
fp_dbg("buffer size %zd", buflen);
|
|
||||||
if (buflen < sizeof(*raw))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (strncmp(raw->prefix, "FP1", 3) == 0) {
|
|
||||||
return fpi_print_data_from_fp1_data(buf, buflen);
|
|
||||||
} else if (strncmp(raw->prefix, "FP2", 3) == 0) {
|
|
||||||
return fpi_print_data_from_fp2_data(buf, buflen);
|
|
||||||
} else {
|
|
||||||
fp_dbg("bad header prefix");
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_print_data_save:
|
|
||||||
* @data: the stored print to save to disk
|
|
||||||
* @finger: the finger that this print corresponds to
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_print_data_load:
|
|
||||||
* @dev: the device you are loading the print for
|
|
||||||
* @finger: the finger of the file you are loading
|
|
||||||
* @data: output location to put the corresponding stored print. Must be
|
|
||||||
* freed with fp_print_data_free() after use.
|
|
||||||
|
|
||||||
* 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).
|
|
||||||
*
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_print_data_delete:
|
|
||||||
* @dev: the device that the print belongs to
|
|
||||||
* @finger: the finger of the file you are deleting
|
|
||||||
|
|
||||||
* Removes a stored print from disk previously saved with fp_print_data_save().
|
|
||||||
*
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_print_data_from_dscv_print:
|
|
||||||
* @print: the discovered print
|
|
||||||
* @data: output location to point to the corresponding stored print. Must
|
|
||||||
* be freed with fp_print_data_free() after use.
|
|
||||||
|
|
||||||
* Attempts to load a stored print based on a #fp_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).
|
|
||||||
*
|
|
||||||
* Returns: 0 on success, non-zero on error.
|
|
||||||
*
|
|
||||||
* Deprecated: Do not use.
|
|
||||||
*/
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_print_data_free:
|
|
||||||
* @data: the stored print to destroy. If NULL, function simply returns.
|
|
||||||
*
|
|
||||||
* Frees a stored print. Must be called when you are finished using the print.
|
|
||||||
*/
|
|
||||||
API_EXPORTED void fp_print_data_free(struct fp_print_data *data)
|
|
||||||
{
|
|
||||||
if (data)
|
|
||||||
g_slist_free_full(data->prints, (GDestroyNotify)fpi_print_data_item_free);
|
|
||||||
g_free(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_print_data_get_driver_id:
|
|
||||||
* @data: the stored print
|
|
||||||
|
|
||||||
* Gets the [driver ID](advanced-topics.html#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.
|
|
||||||
*
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_print_data_get_devtype:
|
|
||||||
* @data: the stored print
|
|
||||||
|
|
||||||
* Gets the [devtype](advanced-topics.html#device-types) for a stored print. The devtype represents
|
|
||||||
* which type of device under the parent driver is compatible with the 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SECTION:dscv_print
|
|
||||||
* @title: Print discovery (deprecated)
|
|
||||||
*
|
|
||||||
* The [stored print](libfprint-Stored-prints.html) 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 #fp_dscv_print 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.
|
|
||||||
*
|
|
||||||
* Note that this portion of the library is deprecated. All that it offers is
|
|
||||||
* already implementable using publicly available functions, and its usage is
|
|
||||||
* unnecessarily restrictive in terms of how it stores data.
|
|
||||||
*/
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_discover_prints:
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* Deprecated: Do not 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_dscv_prints_free:
|
|
||||||
* @prints: the list of discovered prints. If NULL, function simply
|
|
||||||
* returns.
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* Deprecated: Do not use.
|
|
||||||
*/
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_dscv_print_get_driver_id:
|
|
||||||
* @print: the discovered print
|
|
||||||
*
|
|
||||||
* Gets the [driver ID](advanced-topics.html#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.
|
|
||||||
*
|
|
||||||
* Returns: the driver ID of the driver compatible with the print
|
|
||||||
*
|
|
||||||
* Deprecated: Do not use.
|
|
||||||
*/
|
|
||||||
API_EXPORTED uint16_t fp_dscv_print_get_driver_id(struct fp_dscv_print *print)
|
|
||||||
{
|
|
||||||
return print->driver_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_dscv_print_get_devtype:
|
|
||||||
* @print: the discovered print
|
|
||||||
*
|
|
||||||
* Gets the [devtype](advanced-topics.html#device-types) for a discovered print. The devtype
|
|
||||||
* represents which type of device under the parent driver is compatible
|
|
||||||
* with the print.
|
|
||||||
*
|
|
||||||
* Returns: the devtype of the device range compatible with the print
|
|
||||||
*
|
|
||||||
* Deprecated: Do not use.
|
|
||||||
*/
|
|
||||||
API_EXPORTED uint32_t fp_dscv_print_get_devtype(struct fp_dscv_print *print)
|
|
||||||
{
|
|
||||||
return print->devtype;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_dscv_print_get_finger:
|
|
||||||
* @print: discovered print
|
|
||||||
*
|
|
||||||
* Gets the finger code for a discovered print.
|
|
||||||
*
|
|
||||||
* Returns: a finger code from #fp_finger
|
|
||||||
*
|
|
||||||
* Deprecated: Do not use.
|
|
||||||
*/
|
|
||||||
API_EXPORTED enum fp_finger fp_dscv_print_get_finger(struct fp_dscv_print *print)
|
|
||||||
{
|
|
||||||
return print->finger;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fp_dscv_print_delete:
|
|
||||||
* @print: the discovered print to remove from disk
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* Returns: 0 on success, negative on error
|
|
||||||
*
|
|
||||||
* Deprecated: Do not use.
|
|
||||||
*/
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -28,9 +28,10 @@
|
|||||||
#include "drivers_api.h"
|
#include "drivers_api.h"
|
||||||
#include "aeslib.h"
|
#include "aeslib.h"
|
||||||
|
|
||||||
static void start_capture(struct fp_img_dev *dev);
|
static void start_capture (FpImageDevice *dev);
|
||||||
static void complete_deactivation(struct fp_img_dev *dev);
|
static void complete_deactivation (FpImageDevice *dev);
|
||||||
static int adjust_gain(unsigned char *buffer, int status);
|
static int adjust_gain (unsigned char *buffer,
|
||||||
|
int status);
|
||||||
|
|
||||||
#define FIRST_AES1610_REG 0x1B
|
#define FIRST_AES1610_REG 0x1B
|
||||||
#define LAST_AES1610_REG 0xFF
|
#define LAST_AES1610_REG 0xFF
|
||||||
@@ -39,11 +40,14 @@ static int adjust_gain(unsigned char *buffer, int status);
|
|||||||
#define GAIN_STATUS_NORMAL 2
|
#define GAIN_STATUS_NORMAL 2
|
||||||
|
|
||||||
/* FIXME these need checking */
|
/* FIXME these need checking */
|
||||||
#define EP_IN (1 | LIBUSB_ENDPOINT_IN)
|
#define EP_IN (1 | FPI_USB_ENDPOINT_IN)
|
||||||
#define EP_OUT (2 | LIBUSB_ENDPOINT_OUT)
|
#define EP_OUT (2 | FPI_USB_ENDPOINT_OUT)
|
||||||
|
|
||||||
#define BULK_TIMEOUT 4000
|
#define BULK_TIMEOUT 4000
|
||||||
|
|
||||||
|
#define FINGER_DETECTION_LEN 19
|
||||||
|
#define STRIP_CAPTURE_LEN 665
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The AES1610 is an imaging device using a swipe-type sensor. It samples
|
* The AES1610 is an imaging device using a swipe-type sensor. It samples
|
||||||
* the finger at preprogrammed intervals, sending a 128x8 frame to the
|
* the finger at preprogrammed intervals, sending a 128x8 frame to the
|
||||||
@@ -66,13 +70,19 @@ static int adjust_gain(unsigned char *buffer, int status);
|
|||||||
|
|
||||||
/****** GENERAL FUNCTIONS ******/
|
/****** GENERAL FUNCTIONS ******/
|
||||||
|
|
||||||
struct aes1610_dev {
|
struct _FpiDeviceAes1610
|
||||||
uint8_t read_regs_retry_count;
|
{
|
||||||
|
FpImageDevice parent;
|
||||||
|
|
||||||
|
guint8 read_regs_retry_count;
|
||||||
GSList *strips;
|
GSList *strips;
|
||||||
size_t strips_len;
|
gsize strips_len;
|
||||||
gboolean deactivating;
|
gboolean deactivating;
|
||||||
uint8_t blanks_count;
|
guint8 blanks_count;
|
||||||
};
|
};
|
||||||
|
G_DECLARE_FINAL_TYPE (FpiDeviceAes1610, fpi_device_aes1610, FPI, DEVICE_AES1610,
|
||||||
|
FpImageDevice);
|
||||||
|
G_DEFINE_TYPE (FpiDeviceAes1610, fpi_device_aes1610, FP_TYPE_IMAGE_DEVICE);
|
||||||
|
|
||||||
static struct fpi_frame_asmbl_ctx assembling_ctx = {
|
static struct fpi_frame_asmbl_ctx assembling_ctx = {
|
||||||
.frame_width = FRAME_WIDTH,
|
.frame_width = FRAME_WIDTH,
|
||||||
@@ -81,74 +91,58 @@ static struct fpi_frame_asmbl_ctx assembling_ctx = {
|
|||||||
.get_pixel = aes_get_pixel,
|
.get_pixel = aes_get_pixel,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef void (*aes1610_read_regs_cb)(struct fp_img_dev *dev, int status,
|
typedef void (*aes1610_read_regs_cb)(FpImageDevice *dev,
|
||||||
unsigned char *regs, void *user_data);
|
int status,
|
||||||
|
unsigned char *regs,
|
||||||
|
void *user_data);
|
||||||
|
|
||||||
struct aes1610_read_regs {
|
struct aes1610_read_regs
|
||||||
struct fp_img_dev *dev;
|
{
|
||||||
|
FpImageDevice *dev;
|
||||||
aes1610_read_regs_cb callback;
|
aes1610_read_regs_cb callback;
|
||||||
struct aes_regwrite *regwrite;
|
struct aes_regwrite *regwrite;
|
||||||
void *user_data;
|
void *user_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* FIXME: what to do here? */
|
/* FIXME: what to do here? */
|
||||||
static void stub_capture_stop_cb(struct fp_img_dev *dev, int result, void *user_data)
|
static void
|
||||||
{
|
stub_capture_stop_cb (FpImageDevice *dev, GError *error,
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* check that read succeeded but ignore all data */
|
|
||||||
static void generic_ignore_data_cb(struct libusb_transfer *transfer)
|
|
||||||
{
|
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
|
||||||
|
|
||||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
|
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
|
||||||
else if (transfer->length != transfer->actual_length)
|
|
||||||
fpi_ssm_mark_aborted(ssm, -EPROTO);
|
|
||||||
else
|
|
||||||
fpi_ssm_next_state(ssm);
|
|
||||||
|
|
||||||
g_free(transfer->buffer);
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void generic_write_regv_cb(struct fp_img_dev *dev, int result,
|
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = user_data;
|
if (error)
|
||||||
if (result == 0)
|
{
|
||||||
|
fp_warn ("Error stopping capture: %s", error->message);
|
||||||
|
g_error_free (error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
generic_write_regv_cb (FpImageDevice *dev, GError *error,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
FpiSsm *ssm = user_data;
|
||||||
|
|
||||||
|
if (!error)
|
||||||
fpi_ssm_next_state (ssm);
|
fpi_ssm_next_state (ssm);
|
||||||
else
|
else
|
||||||
fpi_ssm_mark_aborted(ssm, result);
|
fpi_ssm_mark_failed (ssm, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* read the specified number of bytes from the IN endpoint but throw them
|
/* read the specified number of bytes from the IN endpoint but throw them
|
||||||
* away, then increment the SSM */
|
* away, then increment the SSM */
|
||||||
static void generic_read_ignore_data(struct fpi_ssm *ssm, size_t bytes)
|
static void
|
||||||
|
generic_read_ignore_data (FpiSsm *ssm, FpDevice *dev,
|
||||||
|
size_t bytes)
|
||||||
{
|
{
|
||||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
|
||||||
unsigned char *data;
|
unsigned char *data;
|
||||||
struct fp_dev *dev;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
if (!transfer) {
|
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
data = g_malloc (bytes);
|
data = g_malloc (bytes);
|
||||||
dev = fpi_ssm_get_dev(ssm);
|
fpi_usb_transfer_fill_bulk_full (transfer, EP_IN, data, bytes, g_free);
|
||||||
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(dev), EP_IN, data, bytes,
|
transfer->ssm = ssm;
|
||||||
generic_ignore_data_cb, ssm, BULK_TIMEOUT);
|
transfer->short_is_error = TRUE;
|
||||||
|
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
||||||
r = libusb_submit_transfer(transfer);
|
fpi_ssm_usb_transfer_cb, NULL);
|
||||||
if (r < 0) {
|
|
||||||
g_free(data);
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
fpi_ssm_mark_aborted(ssm, r);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/****** FINGER PRESENCE DETECTION ******/
|
/****** FINGER PRESENCE DETECTION ******/
|
||||||
@@ -179,77 +173,67 @@ static const struct aes_regwrite finger_det_reqs[] = {
|
|||||||
{ 0x81, 0x04 }
|
{ 0x81, 0x04 }
|
||||||
};
|
};
|
||||||
|
|
||||||
static void start_finger_detection(struct fp_img_dev *dev);
|
static void start_finger_detection (FpImageDevice *dev);
|
||||||
|
|
||||||
static void finger_det_data_cb(struct libusb_transfer *transfer)
|
static void
|
||||||
|
finger_det_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
|
gpointer user_data, GError *error)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = transfer->user_data;
|
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
|
||||||
unsigned char *data = transfer->buffer;
|
unsigned char *data = transfer->buffer;
|
||||||
int i;
|
int i;
|
||||||
int sum = 0;
|
int sum = 0;
|
||||||
|
|
||||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
if (error)
|
||||||
fpi_imgdev_session_error(dev, -EIO);
|
{
|
||||||
goto out;
|
fpi_image_device_session_error (dev, error);
|
||||||
} else if (transfer->length != transfer->actual_length) {
|
return;
|
||||||
fpi_imgdev_session_error(dev, -EPROTO);
|
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* examine histogram to determine finger presence */
|
/* examine histogram to determine finger presence */
|
||||||
for (i = 3; i < 17; i++)
|
for (i = 3; i < 17; i++)
|
||||||
sum += (data[i] & 0xf) + (data[i] >> 4);
|
sum += (data[i] & 0xf) + (data[i] >> 4);
|
||||||
if (sum > 20) {
|
if (sum > 20)
|
||||||
|
{
|
||||||
/* reset default gain */
|
/* reset default gain */
|
||||||
adjust_gain (data, GAIN_STATUS_FIRST);
|
adjust_gain (data, GAIN_STATUS_FIRST);
|
||||||
/* finger present, start capturing */
|
/* finger present, start capturing */
|
||||||
fpi_imgdev_report_finger_status(dev, TRUE);
|
fpi_image_device_report_finger_status (dev, TRUE);
|
||||||
start_capture (dev);
|
start_capture (dev);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/* no finger, poll for a new histogram */
|
/* no finger, poll for a new histogram */
|
||||||
start_finger_detection (dev);
|
start_finger_detection (dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
|
||||||
g_free(data);
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void finger_det_reqs_cb(struct fp_img_dev *dev, int result, void *user_data)
|
static void
|
||||||
|
finger_det_reqs_cb (FpImageDevice *dev, GError *error,
|
||||||
|
void *user_data)
|
||||||
{
|
{
|
||||||
struct libusb_transfer *transfer;
|
FpiUsbTransfer *transfer;
|
||||||
unsigned char *data;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
if (result) {
|
if (error)
|
||||||
fpi_imgdev_session_error(dev, result);
|
{
|
||||||
|
fpi_image_device_session_error (dev, error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
transfer = libusb_alloc_transfer(0);
|
transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
|
||||||
if (!transfer) {
|
fpi_usb_transfer_fill_bulk (transfer, EP_IN, FINGER_DETECTION_LEN);
|
||||||
fpi_imgdev_session_error(dev, -ENOMEM);
|
transfer->short_is_error = TRUE;
|
||||||
return;
|
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
||||||
|
finger_det_data_cb, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
data = g_malloc(19);
|
static void
|
||||||
libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), EP_IN, data, 19,
|
start_finger_detection (FpImageDevice *dev)
|
||||||
finger_det_data_cb, dev, BULK_TIMEOUT);
|
|
||||||
|
|
||||||
r = libusb_submit_transfer(transfer);
|
|
||||||
if (r < 0) {
|
|
||||||
g_free(data);
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
fpi_imgdev_session_error(dev, r);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static void start_finger_detection(struct fp_img_dev *dev)
|
|
||||||
{
|
{
|
||||||
struct aes1610_dev *aesdev = fpi_imgdev_get_user_data(dev);
|
FpiDeviceAes1610 *self = FPI_DEVICE_AES1610 (dev);
|
||||||
|
|
||||||
if (aesdev->deactivating) {
|
if (self->deactivating)
|
||||||
|
{
|
||||||
complete_deactivation (dev);
|
complete_deactivation (dev);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -413,36 +397,42 @@ static unsigned char list_BD_values[10] = {
|
|||||||
/*
|
/*
|
||||||
* Adjust the gain according to the histogram data
|
* Adjust the gain according to the histogram data
|
||||||
* 0xbd, 0xbe, 0x29 and 0x2A registers are affected
|
* 0xbd, 0xbe, 0x29 and 0x2A registers are affected
|
||||||
* Returns 0 if no problem occured
|
* Returns 0 if no problem occurred
|
||||||
* TODO: This is a basic support for gain. It needs testing/tweaking. */
|
* TODO: This is a basic support for gain. It needs testing/tweaking. */
|
||||||
static int adjust_gain(unsigned char *buffer, int status)
|
static int
|
||||||
|
adjust_gain (unsigned char *buffer, int status)
|
||||||
{
|
{
|
||||||
// The position in the array of possible values for 0xBE and 0xBD registers
|
// The position in the array of possible values for 0xBE and 0xBD registers
|
||||||
static int pos_list_BE = 0;
|
static int pos_list_BE = 0;
|
||||||
static int pos_list_BD = 0;
|
static int pos_list_BD = 0;
|
||||||
|
|
||||||
// This is the first adjustement (we begin acquisition)
|
// This is the first adjustment (we begin acquisition)
|
||||||
// We adjust strip_scan_reqs for future strips and capture_reqs that is sent just after this step
|
// We adjust strip_scan_reqs for future strips and capture_reqs that is sent just after this step
|
||||||
if (status == GAIN_STATUS_FIRST) {
|
if (status == GAIN_STATUS_FIRST)
|
||||||
if (buffer[1] > 0x78) { // maximum gain needed
|
{
|
||||||
|
if (buffer[1] > 0x78) // maximum gain needed
|
||||||
|
{
|
||||||
strip_scan_reqs[0].value = 0x6B;
|
strip_scan_reqs[0].value = 0x6B;
|
||||||
strip_scan_reqs[1].value = 0x06;
|
strip_scan_reqs[1].value = 0x06;
|
||||||
strip_scan_reqs[2].value = 0x35;
|
strip_scan_reqs[2].value = 0x35;
|
||||||
strip_scan_reqs[3].value = 0x4B;
|
strip_scan_reqs[3].value = 0x4B;
|
||||||
}
|
}
|
||||||
else if (buffer[1] > 0x55) {
|
else if (buffer[1] > 0x55)
|
||||||
|
{
|
||||||
strip_scan_reqs[0].value = 0x63;
|
strip_scan_reqs[0].value = 0x63;
|
||||||
strip_scan_reqs[1].value = 0x15;
|
strip_scan_reqs[1].value = 0x15;
|
||||||
strip_scan_reqs[2].value = 0x35;
|
strip_scan_reqs[2].value = 0x35;
|
||||||
strip_scan_reqs[3].value = 0x3b;
|
strip_scan_reqs[3].value = 0x3b;
|
||||||
}
|
}
|
||||||
else if (buffer[1] > 0x40 || buffer[16] > 0x19) {
|
else if (buffer[1] > 0x40 || buffer[16] > 0x19)
|
||||||
|
{
|
||||||
strip_scan_reqs[0].value = 0x43;
|
strip_scan_reqs[0].value = 0x43;
|
||||||
strip_scan_reqs[1].value = 0x13;
|
strip_scan_reqs[1].value = 0x13;
|
||||||
strip_scan_reqs[2].value = 0x35;
|
strip_scan_reqs[2].value = 0x35;
|
||||||
strip_scan_reqs[3].value = 0x30;
|
strip_scan_reqs[3].value = 0x30;
|
||||||
}
|
}
|
||||||
else { // minimum gain needed
|
else // minimum gain needed
|
||||||
|
{
|
||||||
strip_scan_reqs[0].value = 0x23;
|
strip_scan_reqs[0].value = 0x23;
|
||||||
strip_scan_reqs[1].value = 0x07;
|
strip_scan_reqs[1].value = 0x07;
|
||||||
strip_scan_reqs[2].value = 0x35;
|
strip_scan_reqs[2].value = 0x35;
|
||||||
@@ -457,12 +447,13 @@ static int adjust_gain(unsigned char *buffer, int status)
|
|||||||
|
|
||||||
fp_dbg ("first gain: %x %x %x %x %x %x %x %x", strip_scan_reqs[0].reg, strip_scan_reqs[0].value, strip_scan_reqs[1].reg, strip_scan_reqs[1].value, strip_scan_reqs[2].reg, strip_scan_reqs[2].value, strip_scan_reqs[3].reg, strip_scan_reqs[3].value);
|
fp_dbg ("first gain: %x %x %x %x %x %x %x %x", strip_scan_reqs[0].reg, strip_scan_reqs[0].value, strip_scan_reqs[1].reg, strip_scan_reqs[1].value, strip_scan_reqs[2].reg, strip_scan_reqs[2].value, strip_scan_reqs[3].reg, strip_scan_reqs[3].value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Every 2/3 strips
|
// Every 2/3 strips
|
||||||
// We try to soften big changes of the gain (at least for 0xBE and 0xBD
|
// We try to soften big changes of the gain (at least for 0xBE and 0xBD
|
||||||
// FIXME: This softenning will need testing and tweaking too
|
// FIXME: This softenning will need testing and tweaking too
|
||||||
else if (status == GAIN_STATUS_NORMAL) {
|
else if (status == GAIN_STATUS_NORMAL)
|
||||||
if (buffer[514] > 0x78) { // maximum gain needed
|
{
|
||||||
|
if (buffer[514] > 0x78) // maximum gain needed
|
||||||
|
{
|
||||||
if (pos_list_BE < 7)
|
if (pos_list_BE < 7)
|
||||||
pos_list_BE++;
|
pos_list_BE++;
|
||||||
|
|
||||||
@@ -472,7 +463,8 @@ static int adjust_gain(unsigned char *buffer, int status)
|
|||||||
strip_scan_reqs[1].value = 0x04;
|
strip_scan_reqs[1].value = 0x04;
|
||||||
strip_scan_reqs[2].value = 0x35;
|
strip_scan_reqs[2].value = 0x35;
|
||||||
}
|
}
|
||||||
else if (buffer[514] > 0x55) {
|
else if (buffer[514] > 0x55)
|
||||||
|
{
|
||||||
if (pos_list_BE < 2)
|
if (pos_list_BE < 2)
|
||||||
pos_list_BE++;
|
pos_list_BE++;
|
||||||
else if (pos_list_BE > 2)
|
else if (pos_list_BE > 2)
|
||||||
@@ -486,7 +478,8 @@ static int adjust_gain(unsigned char *buffer, int status)
|
|||||||
strip_scan_reqs[1].value = 0x15;
|
strip_scan_reqs[1].value = 0x15;
|
||||||
strip_scan_reqs[2].value = 0x35;
|
strip_scan_reqs[2].value = 0x35;
|
||||||
}
|
}
|
||||||
else if (buffer[514] > 0x40 || buffer[529] > 0x19) {
|
else if (buffer[514] > 0x40 || buffer[529] > 0x19)
|
||||||
|
{
|
||||||
if (pos_list_BE < 1)
|
if (pos_list_BE < 1)
|
||||||
pos_list_BE++;
|
pos_list_BE++;
|
||||||
else if (pos_list_BE > 1)
|
else if (pos_list_BE > 1)
|
||||||
@@ -500,7 +493,8 @@ static int adjust_gain(unsigned char *buffer, int status)
|
|||||||
strip_scan_reqs[1].value = 0x13;
|
strip_scan_reqs[1].value = 0x13;
|
||||||
strip_scan_reqs[2].value = 0x35;
|
strip_scan_reqs[2].value = 0x35;
|
||||||
}
|
}
|
||||||
else { // minimum gain needed
|
else // minimum gain needed
|
||||||
|
{
|
||||||
if (pos_list_BE > 0)
|
if (pos_list_BE > 0)
|
||||||
pos_list_BE--;
|
pos_list_BE--;
|
||||||
|
|
||||||
@@ -517,7 +511,8 @@ static int adjust_gain(unsigned char *buffer, int status)
|
|||||||
fp_dbg ("gain: %x %x %x %x %x %x %x %x", strip_scan_reqs[0].reg, strip_scan_reqs[0].value, strip_scan_reqs[1].reg, strip_scan_reqs[1].value, strip_scan_reqs[2].reg, strip_scan_reqs[2].value, strip_scan_reqs[3].reg, strip_scan_reqs[3].value);
|
fp_dbg ("gain: %x %x %x %x %x %x %x %x", strip_scan_reqs[0].reg, strip_scan_reqs[0].value, strip_scan_reqs[1].reg, strip_scan_reqs[1].value, strip_scan_reqs[2].reg, strip_scan_reqs[2].value, strip_scan_reqs[3].reg, strip_scan_reqs[3].value);
|
||||||
}
|
}
|
||||||
// Unknown status
|
// Unknown status
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
fp_err ("Unexpected gain status.");
|
fp_err ("Unexpected gain status.");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -527,7 +522,8 @@ static int adjust_gain(unsigned char *buffer, int status)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Restore the default gain values */
|
* Restore the default gain values */
|
||||||
static void restore_gain(void)
|
static void
|
||||||
|
restore_gain (void)
|
||||||
{
|
{
|
||||||
strip_scan_reqs[0].value = list_BE_values[0];
|
strip_scan_reqs[0].value = list_BE_values[0];
|
||||||
strip_scan_reqs[1].value = 0x04;
|
strip_scan_reqs[1].value = 0x04;
|
||||||
@@ -543,7 +539,7 @@ static void restore_gain(void)
|
|||||||
|
|
||||||
/* capture SM movement:
|
/* capture SM movement:
|
||||||
* request and read strip,
|
* request and read strip,
|
||||||
* jump back to request UNLESS theres no finger, in which case exit SM,
|
* jump back to request UNLESS there's no finger, in which case exit SM,
|
||||||
* report lack of finger presence, and move to finger detection */
|
* report lack of finger presence, and move to finger detection */
|
||||||
|
|
||||||
enum capture_states {
|
enum capture_states {
|
||||||
@@ -554,170 +550,168 @@ enum capture_states {
|
|||||||
CAPTURE_NUM_STATES,
|
CAPTURE_NUM_STATES,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void capture_read_strip_cb(struct libusb_transfer *transfer)
|
static void
|
||||||
|
capture_read_strip_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
|
gpointer user_data, GError *error)
|
||||||
{
|
{
|
||||||
unsigned char *stripdata;
|
unsigned char *stripdata;
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
|
||||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
FpiDeviceAes1610 *self = FPI_DEVICE_AES1610 (dev);
|
||||||
struct aes1610_dev *aesdev = fpi_imgdev_get_user_data(dev);
|
|
||||||
unsigned char *data = transfer->buffer;
|
unsigned char *data = transfer->buffer;
|
||||||
int sum, i;
|
gint sum, i;
|
||||||
|
|
||||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
if (error)
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
{
|
||||||
goto out;
|
fpi_ssm_mark_failed (transfer->ssm, error);
|
||||||
} else if (transfer->length != transfer->actual_length) {
|
return;
|
||||||
fpi_ssm_mark_aborted(ssm, -EPROTO);
|
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME: would preallocating strip buffers be a decent optimization? */
|
/* FIXME: would preallocating strip buffers be a decent optimization? */
|
||||||
|
|
||||||
sum = 0;
|
sum = 0;
|
||||||
for (i = 516; i < 530; i++)
|
for (i = 516; i < 530; i++)
|
||||||
{
|
|
||||||
/* histogram[i] = number of pixels of value i
|
/* histogram[i] = number of pixels of value i
|
||||||
Only the pixel values from 10 to 15 are used to detect finger. */
|
Only the pixel values from 10 to 15 are used to detect finger. */
|
||||||
sum += data[i];
|
sum += data[i];
|
||||||
}
|
|
||||||
|
|
||||||
if (sum > 0) {
|
fp_dbg ("sum=%d", sum);
|
||||||
|
if (sum > 0)
|
||||||
|
{
|
||||||
/* FIXME: would preallocating strip buffers be a decent optimization? */
|
/* FIXME: would preallocating strip buffers be a decent optimization? */
|
||||||
struct fpi_frame *stripe = g_malloc (FRAME_WIDTH * (FRAME_HEIGHT / 2) + sizeof (struct fpi_frame));
|
struct fpi_frame *stripe = g_malloc (FRAME_WIDTH * (FRAME_HEIGHT / 2) + sizeof (struct fpi_frame));
|
||||||
stripe->delta_x = 0;
|
stripe->delta_x = 0;
|
||||||
stripe->delta_y = 0;
|
stripe->delta_y = 0;
|
||||||
stripdata = stripe->data;
|
stripdata = stripe->data;
|
||||||
memcpy (stripdata, data + 1, FRAME_WIDTH * (FRAME_HEIGHT / 2));
|
memcpy (stripdata, data + 1, FRAME_WIDTH * (FRAME_HEIGHT / 2));
|
||||||
aesdev->strips = g_slist_prepend(aesdev->strips, stripe);
|
self->strips = g_slist_prepend (self->strips, stripe);
|
||||||
aesdev->strips_len++;
|
self->strips_len++;
|
||||||
aesdev->blanks_count = 0;
|
self->blanks_count = 0;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
if (sum < 0) {
|
{
|
||||||
fpi_ssm_mark_aborted(ssm, sum);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
fp_dbg("sum=%d", sum);
|
|
||||||
|
|
||||||
/* FIXME: 0 might be too low as a threshold */
|
/* FIXME: 0 might be too low as a threshold */
|
||||||
/* FIXME: sometimes we get 0 in the middle of a scan, should we wait for
|
/* FIXME: sometimes we get 0 in the middle of a scan, should we wait for
|
||||||
* a few consecutive zeroes? */
|
* a few consecutive zeroes? */
|
||||||
|
|
||||||
/* If sum is 0 for a reasonable # of frames, finger has been removed */
|
/* sum cannot be negative, so is 0 */
|
||||||
if (sum == 0) {
|
self->blanks_count++;
|
||||||
aesdev->blanks_count++;
|
|
||||||
fp_dbg ("got blank frame");
|
fp_dbg ("got blank frame");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* use histogram data above for gain calibration (0xbd, 0xbe, 0x29 and 0x2A ) */
|
/* use histogram data above for gain calibration (0xbd, 0xbe, 0x29 and 0x2A ) */
|
||||||
adjust_gain (data, GAIN_STATUS_NORMAL);
|
adjust_gain (data, GAIN_STATUS_NORMAL);
|
||||||
|
|
||||||
/* stop capturing if MAX_FRAMES is reached */
|
/* stop capturing if MAX_FRAMES is reached */
|
||||||
if (aesdev->blanks_count > 10 || g_slist_length(aesdev->strips) >= MAX_FRAMES) {
|
if (self->blanks_count > 10 || g_slist_length (self->strips) >= MAX_FRAMES)
|
||||||
struct fp_img *img;
|
{
|
||||||
|
FpImage *img;
|
||||||
|
|
||||||
fp_dbg("sending stop capture.... blanks=%d frames=%d", aesdev->blanks_count, g_slist_length(aesdev->strips));
|
fp_dbg ("sending stop capture.... blanks=%d frames=%d",
|
||||||
|
self->blanks_count, g_slist_length (self->strips));
|
||||||
/* send stop capture bits */
|
/* send stop capture bits */
|
||||||
aes_write_regv (dev, capture_stop, G_N_ELEMENTS (capture_stop), stub_capture_stop_cb, NULL);
|
aes_write_regv (dev, capture_stop, G_N_ELEMENTS (capture_stop), stub_capture_stop_cb, NULL);
|
||||||
aesdev->strips = g_slist_reverse(aesdev->strips);
|
self->strips = g_slist_reverse (self->strips);
|
||||||
fpi_do_movement_estimation(&assembling_ctx, aesdev->strips, aesdev->strips_len);
|
fpi_do_movement_estimation (&assembling_ctx, self->strips);
|
||||||
img = fpi_assemble_frames(&assembling_ctx, aesdev->strips, aesdev->strips_len);
|
img = fpi_assemble_frames (&assembling_ctx, self->strips);
|
||||||
img->flags |= FP_IMG_PARTIAL;
|
|
||||||
g_slist_free_full(aesdev->strips, g_free);
|
g_slist_free_full (self->strips, g_free);
|
||||||
aesdev->strips = NULL;
|
self->strips = NULL;
|
||||||
aesdev->strips_len = 0;
|
self->strips_len = 0;
|
||||||
aesdev->blanks_count = 0;
|
self->blanks_count = 0;
|
||||||
fpi_imgdev_image_captured(dev, img);
|
fpi_image_device_image_captured (dev, img);
|
||||||
fpi_imgdev_report_finger_status(dev, FALSE);
|
fpi_image_device_report_finger_status (dev, FALSE);
|
||||||
/* marking machine complete will re-trigger finger detection loop */
|
/* marking machine complete will re-trigger finger detection loop */
|
||||||
fpi_ssm_mark_completed(ssm);
|
fpi_ssm_mark_completed (transfer->ssm);
|
||||||
/* Acquisition finished: restore default gain values */
|
/* Acquisition finished: restore default gain values */
|
||||||
restore_gain ();
|
restore_gain ();
|
||||||
} else {
|
|
||||||
/* obtain next strip */
|
|
||||||
fpi_ssm_jump_to_state(ssm, CAPTURE_REQUEST_STRIP);
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
out:
|
|
||||||
g_free(data);
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void capture_run_state(struct fpi_ssm *ssm)
|
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
/* obtain next strip */
|
||||||
struct aes1610_dev *aesdev = fpi_imgdev_get_user_data(dev);
|
fpi_ssm_jump_to_state (transfer->ssm, CAPTURE_REQUEST_STRIP);
|
||||||
int r;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
static void
|
||||||
|
capture_run_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
|
{
|
||||||
|
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
|
||||||
|
FpiDeviceAes1610 *self = FPI_DEVICE_AES1610 (_dev);
|
||||||
|
|
||||||
|
switch (fpi_ssm_get_cur_state (ssm))
|
||||||
|
{
|
||||||
case CAPTURE_WRITE_REQS:
|
case CAPTURE_WRITE_REQS:
|
||||||
fp_dbg ("write reqs");
|
fp_dbg ("write reqs");
|
||||||
aes_write_regv (dev, capture_reqs, G_N_ELEMENTS (capture_reqs),
|
aes_write_regv (dev, capture_reqs, G_N_ELEMENTS (capture_reqs),
|
||||||
generic_write_regv_cb, ssm);
|
generic_write_regv_cb, ssm);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CAPTURE_READ_DATA:
|
case CAPTURE_READ_DATA:
|
||||||
fp_dbg ("read data");
|
fp_dbg ("read data");
|
||||||
generic_read_ignore_data(ssm, 665);
|
generic_read_ignore_data (ssm, _dev, STRIP_CAPTURE_LEN);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CAPTURE_REQUEST_STRIP:
|
case CAPTURE_REQUEST_STRIP:
|
||||||
fp_dbg ("request strip");
|
fp_dbg ("request strip");
|
||||||
if (aesdev->deactivating)
|
if (self->deactivating)
|
||||||
fpi_ssm_mark_completed (ssm);
|
fpi_ssm_mark_completed (ssm);
|
||||||
else
|
else
|
||||||
aes_write_regv (dev, strip_scan_reqs, G_N_ELEMENTS (strip_scan_reqs),
|
aes_write_regv (dev, strip_scan_reqs, G_N_ELEMENTS (strip_scan_reqs),
|
||||||
generic_write_regv_cb, ssm);
|
generic_write_regv_cb, ssm);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CAPTURE_READ_STRIP:;
|
case CAPTURE_READ_STRIP:;
|
||||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
FpiUsbTransfer *transfer = fpi_usb_transfer_new (_dev);
|
||||||
unsigned char *data;
|
|
||||||
|
|
||||||
if (!transfer) {
|
fpi_usb_transfer_fill_bulk (transfer, EP_IN, STRIP_CAPTURE_LEN);
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
transfer->ssm = ssm;
|
||||||
|
transfer->short_is_error = TRUE;
|
||||||
|
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
||||||
|
capture_read_strip_cb, NULL);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
;
|
||||||
data = g_malloc(665);
|
|
||||||
libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), EP_IN, data, 665,
|
|
||||||
capture_read_strip_cb, ssm, BULK_TIMEOUT);
|
|
||||||
|
|
||||||
r = libusb_submit_transfer(transfer);
|
|
||||||
if (r < 0) {
|
|
||||||
g_free(data);
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
fpi_ssm_mark_aborted(ssm, r);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void capture_sm_complete(struct fpi_ssm *ssm)
|
static void
|
||||||
|
capture_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
|
||||||
struct aes1610_dev *aesdev = fpi_imgdev_get_user_data(dev);
|
FpiDeviceAes1610 *self = FPI_DEVICE_AES1610 (_dev);
|
||||||
|
|
||||||
G_DEBUG_HERE ();
|
G_DEBUG_HERE ();
|
||||||
if (aesdev->deactivating)
|
if (self->deactivating)
|
||||||
|
{
|
||||||
complete_deactivation (dev);
|
complete_deactivation (dev);
|
||||||
else if (fpi_ssm_get_error(ssm))
|
if (error)
|
||||||
fpi_imgdev_session_error(dev, fpi_ssm_get_error(ssm));
|
g_error_free (error);
|
||||||
|
}
|
||||||
|
else if (error)
|
||||||
|
{
|
||||||
|
fpi_image_device_session_error (dev, error);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
start_finger_detection (dev);
|
start_finger_detection (dev);
|
||||||
fpi_ssm_free(ssm);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void start_capture(struct fp_img_dev *dev)
|
static void
|
||||||
|
start_capture (FpImageDevice *dev)
|
||||||
{
|
{
|
||||||
struct aes1610_dev *aesdev = fpi_imgdev_get_user_data(dev);
|
FpiDeviceAes1610 *self = FPI_DEVICE_AES1610 (dev);
|
||||||
struct fpi_ssm *ssm;
|
FpiSsm *ssm;
|
||||||
|
|
||||||
if (aesdev->deactivating) {
|
if (self->deactivating)
|
||||||
|
{
|
||||||
complete_deactivation (dev);
|
complete_deactivation (dev);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssm = fpi_ssm_new(fpi_imgdev_get_dev(dev), capture_run_state, CAPTURE_NUM_STATES);
|
ssm = fpi_ssm_new (FP_DEVICE (dev), capture_run_state,
|
||||||
|
CAPTURE_NUM_STATES);
|
||||||
G_DEBUG_HERE ();
|
G_DEBUG_HERE ();
|
||||||
fpi_ssm_set_user_data(ssm, dev);
|
|
||||||
fpi_ssm_start (ssm, capture_sm_complete);
|
fpi_ssm_start (ssm, capture_sm_complete);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -738,13 +732,15 @@ enum activate_states {
|
|||||||
ACTIVATE_NUM_STATES,
|
ACTIVATE_NUM_STATES,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void activate_run_state(struct fpi_ssm *ssm)
|
static void
|
||||||
|
activate_run_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
|
||||||
|
|
||||||
/* activation on aes1610 seems much more straightforward compared to aes2501 */
|
/* activation on aes1610 seems much more straightforward compared to aes2501 */
|
||||||
/* verify theres anything missing here */
|
/* verify there's anything missing here */
|
||||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
switch (fpi_ssm_get_cur_state (ssm))
|
||||||
|
{
|
||||||
case WRITE_INIT:
|
case WRITE_INIT:
|
||||||
fp_dbg ("write init");
|
fp_dbg ("write init");
|
||||||
aes_write_regv (dev, init, G_N_ELEMENTS (init), generic_write_regv_cb, ssm);
|
aes_write_regv (dev, init, G_N_ELEMENTS (init), generic_write_regv_cb, ssm);
|
||||||
@@ -753,101 +749,110 @@ static void activate_run_state(struct fpi_ssm *ssm)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* jump to finger detection */
|
/* jump to finger detection */
|
||||||
static void activate_sm_complete(struct fpi_ssm *ssm)
|
static void
|
||||||
|
activate_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
|
||||||
fp_dbg("status %d", fpi_ssm_get_error(ssm));
|
|
||||||
fpi_imgdev_activate_complete(dev, fpi_ssm_get_error(ssm));
|
|
||||||
|
|
||||||
if (!fpi_ssm_get_error(ssm))
|
fpi_image_device_activate_complete (dev, error);
|
||||||
|
|
||||||
|
if (!error)
|
||||||
start_finger_detection (dev);
|
start_finger_detection (dev);
|
||||||
fpi_ssm_free(ssm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
static void
|
||||||
|
dev_activate (FpImageDevice *dev)
|
||||||
{
|
{
|
||||||
struct aes1610_dev *aesdev = fpi_imgdev_get_user_data(dev);
|
FpiDeviceAes1610 *self = FPI_DEVICE_AES1610 (dev);
|
||||||
struct fpi_ssm *ssm = fpi_ssm_new(fpi_imgdev_get_dev(dev), activate_run_state,
|
FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), activate_run_state,
|
||||||
ACTIVATE_NUM_STATES);
|
ACTIVATE_NUM_STATES);
|
||||||
fpi_ssm_set_user_data(ssm, dev);
|
|
||||||
aesdev->read_regs_retry_count = 0;
|
self->read_regs_retry_count = 0;
|
||||||
fpi_ssm_start (ssm, activate_sm_complete);
|
fpi_ssm_start (ssm, activate_sm_complete);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dev_deactivate(struct fp_img_dev *dev)
|
static void
|
||||||
|
dev_deactivate (FpImageDevice *dev)
|
||||||
{
|
{
|
||||||
struct aes1610_dev *aesdev = fpi_imgdev_get_user_data(dev);
|
FpiDeviceAes1610 *self = FPI_DEVICE_AES1610 (dev);
|
||||||
|
|
||||||
/* FIXME: audit cancellation points, probably need more, specifically
|
/* FIXME: audit cancellation points, probably need more, specifically
|
||||||
* in error handling paths? */
|
* in error handling paths? */
|
||||||
aesdev->deactivating = TRUE;
|
self->deactivating = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void complete_deactivation(struct fp_img_dev *dev)
|
static void
|
||||||
|
complete_deactivation (FpImageDevice *dev)
|
||||||
{
|
{
|
||||||
struct aes1610_dev *aesdev = fpi_imgdev_get_user_data(dev);
|
FpiDeviceAes1610 *self = FPI_DEVICE_AES1610 (dev);
|
||||||
|
|
||||||
G_DEBUG_HERE ();
|
G_DEBUG_HERE ();
|
||||||
|
|
||||||
/* FIXME: if we're in the middle of a scan, we should cancel the scan.
|
/* FIXME: if we're in the middle of a scan, we should cancel the scan.
|
||||||
* maybe we can do this with a master reset, unconditionally? */
|
* maybe we can do this with a master reset, unconditionally? */
|
||||||
|
|
||||||
aesdev->deactivating = FALSE;
|
self->deactivating = FALSE;
|
||||||
g_slist_free(aesdev->strips);
|
g_slist_free (self->strips);
|
||||||
aesdev->strips = NULL;
|
self->strips = NULL;
|
||||||
aesdev->strips_len = 0;
|
self->strips_len = 0;
|
||||||
aesdev->blanks_count = 0;
|
self->blanks_count = 0;
|
||||||
fpi_imgdev_deactivate_complete(dev);
|
fpi_image_device_deactivate_complete (dev, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
static void
|
||||||
|
dev_init (FpImageDevice *dev)
|
||||||
{
|
{
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
/* FIXME check endpoints */
|
/* FIXME check endpoints */
|
||||||
int r;
|
|
||||||
struct aes1610_dev *aesdev;
|
|
||||||
|
|
||||||
r = libusb_claim_interface(fpi_imgdev_get_usb_dev(dev), 0);
|
if (!g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error))
|
||||||
if (r < 0) {
|
|
||||||
fp_err("could not claim interface 0: %s", libusb_error_name(r));
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
aesdev = g_malloc0(sizeof(struct aes1610_dev));
|
|
||||||
fpi_imgdev_set_user_data(dev, aesdev);
|
|
||||||
fpi_imgdev_open_complete(dev, 0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dev_deinit(struct fp_img_dev *dev)
|
|
||||||
{
|
{
|
||||||
struct aes1610_dev *aesdev;
|
fpi_image_device_open_complete (dev, error);
|
||||||
aesdev = fpi_imgdev_get_user_data(dev);
|
return;
|
||||||
g_free(aesdev);
|
|
||||||
libusb_release_interface(fpi_imgdev_get_usb_dev(dev), 0);
|
|
||||||
fpi_imgdev_close_complete(dev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct usb_id id_table[] = {
|
fpi_image_device_open_complete (dev, NULL);
|
||||||
{ .vendor = 0x08ff, .product = 0x1600 }, /* AES1600 */
|
}
|
||||||
{ 0, 0, 0, },
|
|
||||||
|
static void
|
||||||
|
dev_deinit (FpImageDevice *dev)
|
||||||
|
{
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)),
|
||||||
|
0, 0, &error);
|
||||||
|
fpi_image_device_close_complete (dev, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const FpIdEntry id_table[] = {
|
||||||
|
{ .vid = 0x08ff, .pid = 0x1600, },/* AES1600 */
|
||||||
|
{ .vid = 0, .pid = 0, .driver_data = 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fp_img_driver aes1610_driver = {
|
static void
|
||||||
.driver = {
|
fpi_device_aes1610_init (FpiDeviceAes1610 *self)
|
||||||
.id = AES1610_ID,
|
{
|
||||||
.name = FP_COMPONENT,
|
}
|
||||||
.full_name = "AuthenTec AES1610",
|
static void
|
||||||
.id_table = id_table,
|
fpi_device_aes1610_class_init (FpiDeviceAes1610Class *klass)
|
||||||
.scan_type = FP_SCAN_TYPE_SWIPE,
|
{
|
||||||
},
|
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
|
||||||
.flags = 0,
|
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
|
||||||
.img_height = -1,
|
|
||||||
.img_width = IMAGE_WIDTH,
|
|
||||||
|
|
||||||
.bz3_threshold = 20,
|
dev_class->id = "aes1610";
|
||||||
|
dev_class->full_name = "AuthenTec AES1610";
|
||||||
|
dev_class->type = FP_DEVICE_TYPE_USB;
|
||||||
|
dev_class->id_table = id_table;
|
||||||
|
dev_class->scan_type = FP_SCAN_TYPE_SWIPE;
|
||||||
|
|
||||||
.open = dev_init,
|
img_class->img_open = dev_init;
|
||||||
.close = dev_deinit,
|
img_class->img_close = dev_deinit;
|
||||||
.activate = dev_activate,
|
img_class->activate = dev_activate;
|
||||||
.deactivate = dev_deactivate,
|
img_class->deactivate = dev_deactivate;
|
||||||
};
|
|
||||||
|
|
||||||
|
img_class->bz3_threshold = 20;
|
||||||
|
|
||||||
|
img_class->img_width = IMAGE_WIDTH;
|
||||||
|
img_class->img_height = -1;
|
||||||
|
}
|
||||||
|
|||||||
@@ -27,6 +27,14 @@
|
|||||||
#define FRAME_WIDTH 128
|
#define FRAME_WIDTH 128
|
||||||
#define IMAGE_WIDTH (FRAME_WIDTH + (FRAME_WIDTH / 2))
|
#define IMAGE_WIDTH (FRAME_WIDTH + (FRAME_WIDTH / 2))
|
||||||
|
|
||||||
|
struct _FpiDeviceAes1660
|
||||||
|
{
|
||||||
|
FpiDeviceAesX660 parent;
|
||||||
|
};
|
||||||
|
G_DECLARE_FINAL_TYPE (FpiDeviceAes1660, fpi_device_aes1660, FPI,
|
||||||
|
DEVICE_AES1660, FpiDeviceAesX660);
|
||||||
|
G_DEFINE_TYPE (FpiDeviceAes1660, fpi_device_aes1660, FPI_TYPE_DEVICE_AES_X660);
|
||||||
|
|
||||||
static struct fpi_frame_asmbl_ctx assembling_ctx = {
|
static struct fpi_frame_asmbl_ctx assembling_ctx = {
|
||||||
.frame_width = FRAME_WIDTH,
|
.frame_width = FRAME_WIDTH,
|
||||||
.frame_height = AESX660_FRAME_HEIGHT,
|
.frame_height = AESX660_FRAME_HEIGHT,
|
||||||
@@ -34,79 +42,54 @@ static struct fpi_frame_asmbl_ctx assembling_ctx = {
|
|||||||
.get_pixel = aes_get_pixel,
|
.get_pixel = aes_get_pixel,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
static const FpIdEntry id_table[] = {
|
||||||
{
|
{ .vid = 0x08ff, .pid = 0x1660, },
|
||||||
/* TODO check that device has endpoints we're using */
|
{ .vid = 0x08ff, .pid = 0x1680, },
|
||||||
int r;
|
{ .vid = 0x08ff, .pid = 0x1681, },
|
||||||
struct aesX660_dev *aesdev;
|
{ .vid = 0x08ff, .pid = 0x1682, },
|
||||||
|
{ .vid = 0x08ff, .pid = 0x1683, },
|
||||||
r = libusb_claim_interface(fpi_imgdev_get_usb_dev(dev), 0);
|
{ .vid = 0x08ff, .pid = 0x1684, },
|
||||||
if (r < 0) {
|
{ .vid = 0x08ff, .pid = 0x1685, },
|
||||||
fp_err("could not claim interface 0: %s", libusb_error_name(r));
|
{ .vid = 0x08ff, .pid = 0x1686, },
|
||||||
return r;
|
{ .vid = 0x08ff, .pid = 0x1687, },
|
||||||
}
|
{ .vid = 0x08ff, .pid = 0x1688, },
|
||||||
|
{ .vid = 0x08ff, .pid = 0x1689, },
|
||||||
aesdev = g_malloc0(sizeof(struct aesX660_dev));
|
{ .vid = 0x08ff, .pid = 0x168a, },
|
||||||
fpi_imgdev_set_user_data(dev, aesdev);
|
{ .vid = 0x08ff, .pid = 0x168b, },
|
||||||
aesdev->buffer = g_malloc0(AES1660_FRAME_SIZE + AESX660_HEADER_SIZE);
|
{ .vid = 0x08ff, .pid = 0x168c, },
|
||||||
aesdev->init_seqs[0] = aes1660_init_1;
|
{ .vid = 0x08ff, .pid = 0x168d, },
|
||||||
aesdev->init_seqs_len[0] = G_N_ELEMENTS(aes1660_init_1);
|
{ .vid = 0x08ff, .pid = 0x168e, },
|
||||||
aesdev->init_seqs[1] = aes1660_init_2;
|
{ .vid = 0x08ff, .pid = 0x168f, },
|
||||||
aesdev->init_seqs_len[1] = G_N_ELEMENTS(aes1660_init_2);
|
{ .vid = 0, .pid = 0, .driver_data = 0 },
|
||||||
aesdev->start_imaging_cmd = (unsigned char *)aes1660_start_imaging_cmd;
|
|
||||||
aesdev->start_imaging_cmd_len = sizeof(aes1660_start_imaging_cmd);
|
|
||||||
aesdev->assembling_ctx = &assembling_ctx;
|
|
||||||
aesdev->extra_img_flags = FP_IMG_PARTIAL;
|
|
||||||
|
|
||||||
fpi_imgdev_open_complete(dev, 0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dev_deinit(struct fp_img_dev *dev)
|
|
||||||
{
|
|
||||||
struct aesX660_dev *aesdev = fpi_imgdev_get_user_data(dev);
|
|
||||||
g_free(aesdev->buffer);
|
|
||||||
g_free(aesdev);
|
|
||||||
libusb_release_interface(fpi_imgdev_get_usb_dev(dev), 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 void
|
||||||
.driver = {
|
fpi_device_aes1660_init (FpiDeviceAes1660 *self)
|
||||||
.id = AES1660_ID,
|
{
|
||||||
.name = FP_COMPONENT,
|
}
|
||||||
.full_name = "AuthenTec AES1660",
|
static void
|
||||||
.id_table = id_table,
|
fpi_device_aes1660_class_init (FpiDeviceAes1660Class *klass)
|
||||||
.scan_type = FP_SCAN_TYPE_SWIPE,
|
{
|
||||||
},
|
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
|
||||||
.flags = 0,
|
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
|
||||||
.img_height = -1,
|
FpiDeviceAesX660Class *aes_class = FPI_DEVICE_AES_X660_CLASS (klass);
|
||||||
.img_width = FRAME_WIDTH + FRAME_WIDTH / 2,
|
|
||||||
.bz3_threshold = 20,
|
|
||||||
|
|
||||||
.open = dev_init,
|
dev_class->id = "aes1660";
|
||||||
.close = dev_deinit,
|
dev_class->full_name = "AuthenTec AES1660";
|
||||||
.activate = aesX660_dev_activate,
|
dev_class->type = FP_DEVICE_TYPE_USB;
|
||||||
.deactivate = aesX660_dev_deactivate,
|
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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -18,8 +18,7 @@
|
|||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __AES1660_H
|
#pragma once
|
||||||
#define __AES1660_H
|
|
||||||
|
|
||||||
#define AES1660_FRAME_SIZE 0x244
|
#define AES1660_FRAME_SIZE 0x244
|
||||||
|
|
||||||
@@ -1986,5 +1985,3 @@ static const unsigned char aes1660_start_imaging_cmd[] = {
|
|||||||
0x55, 0x07, 0x00, 0x80, 0x42, 0x00, 0x7f, 0x00, 0x00, 0x14,
|
0x55, 0x07, 0x00, 0x80, 0x42, 0x00, 0x7f, 0x00, 0x00, 0x14,
|
||||||
0x49, 0x03, 0x00, 0x20, 0x00, 0xc8
|
0x49, 0x03, 0x00, 0x20, 0x00, 0xc8
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -27,15 +27,20 @@
|
|||||||
#include "aeslib.h"
|
#include "aeslib.h"
|
||||||
#include "aes2501.h"
|
#include "aes2501.h"
|
||||||
|
|
||||||
static void start_capture(struct fp_img_dev *dev);
|
static void start_capture (FpImageDevice *dev);
|
||||||
static void complete_deactivation(struct fp_img_dev *dev);
|
static void complete_deactivation (FpImageDevice *dev);
|
||||||
|
|
||||||
/* FIXME these need checking */
|
/* FIXME these need checking */
|
||||||
#define EP_IN (1 | LIBUSB_ENDPOINT_IN)
|
#define EP_IN (1 | FPI_USB_ENDPOINT_IN)
|
||||||
#define EP_OUT (2 | LIBUSB_ENDPOINT_OUT)
|
#define EP_OUT (2 | FPI_USB_ENDPOINT_OUT)
|
||||||
|
|
||||||
#define BULK_TIMEOUT 4000
|
#define BULK_TIMEOUT 4000
|
||||||
|
|
||||||
|
#define FINGER_DETECTION_LEN 20
|
||||||
|
#define READ_REGS_LEN 126
|
||||||
|
#define READ_REGS_RESP_LEN 159
|
||||||
|
#define STRIP_CAPTURE_LEN 1705
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The AES2501 is an imaging device using a swipe-type sensor. It samples
|
* The AES2501 is an imaging device using a swipe-type sensor. It samples
|
||||||
* the finger at preprogrammed intervals, sending a 192x16 frame to the
|
* the finger at preprogrammed intervals, sending a 192x16 frame to the
|
||||||
@@ -58,13 +63,19 @@ static void complete_deactivation(struct fp_img_dev *dev);
|
|||||||
|
|
||||||
/****** GENERAL FUNCTIONS ******/
|
/****** GENERAL FUNCTIONS ******/
|
||||||
|
|
||||||
struct aes2501_dev {
|
struct _FpiDeviceAes2501
|
||||||
uint8_t read_regs_retry_count;
|
{
|
||||||
|
FpImageDevice parent;
|
||||||
|
|
||||||
|
guint8 read_regs_retry_count;
|
||||||
GSList *strips;
|
GSList *strips;
|
||||||
size_t strips_len;
|
size_t strips_len;
|
||||||
gboolean deactivating;
|
gboolean deactivating;
|
||||||
int no_finger_cnt;
|
int no_finger_cnt;
|
||||||
};
|
};
|
||||||
|
G_DECLARE_FINAL_TYPE (FpiDeviceAes2501, fpi_device_aes2501, FPI, DEVICE_AES2501,
|
||||||
|
FpImageDevice);
|
||||||
|
G_DEFINE_TYPE (FpiDeviceAes2501, fpi_device_aes2501, FP_TYPE_IMAGE_DEVICE);
|
||||||
|
|
||||||
static struct fpi_frame_asmbl_ctx assembling_ctx = {
|
static struct fpi_frame_asmbl_ctx assembling_ctx = {
|
||||||
.frame_width = FRAME_WIDTH,
|
.frame_width = FRAME_WIDTH,
|
||||||
@@ -73,73 +84,52 @@ static struct fpi_frame_asmbl_ctx assembling_ctx = {
|
|||||||
.get_pixel = aes_get_pixel,
|
.get_pixel = aes_get_pixel,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef void (*aes2501_read_regs_cb)(struct fp_img_dev *dev, int status,
|
typedef void (*aes2501_read_regs_cb)(FpImageDevice *dev,
|
||||||
unsigned char *regs, void *user_data);
|
GError *error,
|
||||||
|
unsigned char *regs,
|
||||||
|
void *user_data);
|
||||||
|
|
||||||
struct aes2501_read_regs {
|
struct aes2501_read_regs
|
||||||
struct fp_img_dev *dev;
|
{
|
||||||
|
FpImageDevice *dev;
|
||||||
aes2501_read_regs_cb callback;
|
aes2501_read_regs_cb callback;
|
||||||
struct aes_regwrite *regwrite;
|
struct aes_regwrite *regwrite;
|
||||||
void *user_data;
|
void *user_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void read_regs_data_cb(struct libusb_transfer *transfer)
|
static void
|
||||||
{
|
read_regs_data_cb (FpiUsbTransfer *transfer, FpDevice *dev,
|
||||||
struct aes2501_read_regs *rdata = transfer->user_data;
|
gpointer user_data, GError *error)
|
||||||
unsigned char *retdata = NULL;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
|
||||||
r = -EIO;
|
|
||||||
} else if (transfer->length != transfer->actual_length) {
|
|
||||||
r = -EPROTO;
|
|
||||||
} else {
|
|
||||||
r = 0;
|
|
||||||
retdata = transfer->buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
rdata->callback(rdata->dev, r, retdata, rdata->user_data);
|
|
||||||
g_free(rdata);
|
|
||||||
g_free(transfer->buffer);
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void read_regs_rq_cb(struct fp_img_dev *dev, int result, void *user_data)
|
|
||||||
{
|
{
|
||||||
struct aes2501_read_regs *rdata = user_data;
|
struct aes2501_read_regs *rdata = user_data;
|
||||||
struct libusb_transfer *transfer;
|
|
||||||
unsigned char *data;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
g_free(rdata->regwrite);
|
rdata->callback (rdata->dev, error, transfer->buffer, rdata->user_data);
|
||||||
if (result != 0)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
transfer = libusb_alloc_transfer(0);
|
|
||||||
if (!transfer) {
|
|
||||||
result = -ENOMEM;
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
data = g_malloc(126);
|
|
||||||
libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), EP_IN, data, 126,
|
|
||||||
read_regs_data_cb, rdata, BULK_TIMEOUT);
|
|
||||||
|
|
||||||
r = libusb_submit_transfer(transfer);
|
|
||||||
if (r < 0) {
|
|
||||||
g_free(data);
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
result = -EIO;
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
err:
|
|
||||||
rdata->callback(dev, result, NULL, rdata->user_data);
|
|
||||||
g_free (rdata);
|
g_free (rdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void read_regs(struct fp_img_dev *dev, aes2501_read_regs_cb callback,
|
static void
|
||||||
|
read_regs_rq_cb (FpImageDevice *dev, GError *error, void *user_data)
|
||||||
|
{
|
||||||
|
struct aes2501_read_regs *rdata = user_data;
|
||||||
|
FpiUsbTransfer *transfer;
|
||||||
|
|
||||||
|
g_free (rdata->regwrite);
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
rdata->callback (dev, error, NULL, rdata->user_data);
|
||||||
|
g_free (rdata);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
|
||||||
|
transfer->short_is_error = TRUE;
|
||||||
|
fpi_usb_transfer_fill_bulk (transfer, EP_IN, READ_REGS_LEN);
|
||||||
|
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
||||||
|
read_regs_data_cb, rdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
read_regs (FpImageDevice *dev, aes2501_read_regs_cb callback,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
/* FIXME: regwrite is dynamic because of asynchronity. is this really
|
/* FIXME: regwrite is dynamic because of asynchronity. is this really
|
||||||
@@ -160,16 +150,19 @@ static void read_regs(struct fp_img_dev *dev, aes2501_read_regs_cb callback,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Read the value of a specific register from a register dump */
|
/* Read the value of a specific register from a register dump */
|
||||||
static int regval_from_dump(unsigned char *data, uint8_t target)
|
static int
|
||||||
|
regval_from_dump (unsigned char *data, guint8 target)
|
||||||
|
{
|
||||||
|
if (*data != FIRST_AES2501_REG)
|
||||||
{
|
{
|
||||||
if (*data != FIRST_AES2501_REG) {
|
|
||||||
fp_err ("not a register dump");
|
fp_err ("not a register dump");
|
||||||
return -EILSEQ;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(FIRST_AES2501_REG <= target && target <= LAST_AES2501_REG)) {
|
if (!(FIRST_AES2501_REG <= target && target <= LAST_AES2501_REG))
|
||||||
|
{
|
||||||
fp_err ("out of range");
|
fp_err ("out of range");
|
||||||
return -EINVAL;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
target -= FIRST_AES2501_REG;
|
target -= FIRST_AES2501_REG;
|
||||||
@@ -177,71 +170,48 @@ static int regval_from_dump(unsigned char *data, uint8_t target)
|
|||||||
return data[target + 1];
|
return data[target + 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
static void generic_write_regv_cb(struct fp_img_dev *dev, int result,
|
static void
|
||||||
|
generic_write_regv_cb (FpImageDevice *dev, GError *error,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = user_data;
|
FpiSsm *ssm = user_data;
|
||||||
if (result == 0)
|
|
||||||
|
if (!error)
|
||||||
fpi_ssm_next_state (ssm);
|
fpi_ssm_next_state (ssm);
|
||||||
else
|
else
|
||||||
fpi_ssm_mark_aborted(ssm, result);
|
fpi_ssm_mark_failed (ssm, error);
|
||||||
}
|
|
||||||
|
|
||||||
/* check that read succeeded but ignore all data */
|
|
||||||
static void generic_ignore_data_cb(struct libusb_transfer *transfer)
|
|
||||||
{
|
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
|
||||||
|
|
||||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
|
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
|
||||||
else if (transfer->length != transfer->actual_length)
|
|
||||||
fpi_ssm_mark_aborted(ssm, -EPROTO);
|
|
||||||
else
|
|
||||||
fpi_ssm_next_state(ssm);
|
|
||||||
|
|
||||||
g_free(transfer->buffer);
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* read the specified number of bytes from the IN endpoint but throw them
|
/* read the specified number of bytes from the IN endpoint but throw them
|
||||||
* away, then increment the SSM */
|
* away, then increment the SSM */
|
||||||
static void generic_read_ignore_data(struct fpi_ssm *ssm, size_t bytes)
|
static void
|
||||||
|
generic_read_ignore_data (FpiSsm *ssm, FpDevice *dev,
|
||||||
|
size_t bytes)
|
||||||
{
|
{
|
||||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
FpiUsbTransfer *transfer;
|
||||||
unsigned char *data;
|
|
||||||
struct fp_dev *dev = fpi_ssm_get_dev(ssm);
|
|
||||||
int r;
|
|
||||||
|
|
||||||
if (!transfer) {
|
transfer = fpi_usb_transfer_new (dev);
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
transfer->ssm = ssm;
|
||||||
return;
|
transfer->short_is_error = TRUE;
|
||||||
}
|
fpi_usb_transfer_fill_bulk (transfer, EP_IN, bytes);
|
||||||
|
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
||||||
data = g_malloc(bytes);
|
fpi_ssm_usb_transfer_cb, NULL);
|
||||||
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(dev), EP_IN, data, bytes,
|
|
||||||
generic_ignore_data_cb, ssm, BULK_TIMEOUT);
|
|
||||||
|
|
||||||
r = libusb_submit_transfer(transfer);
|
|
||||||
if (r < 0) {
|
|
||||||
g_free(data);
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
fpi_ssm_mark_aborted(ssm, r);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/****** IMAGE PROCESSING ******/
|
/****** IMAGE PROCESSING ******/
|
||||||
|
|
||||||
static int sum_histogram_values(unsigned char *data, uint8_t threshold)
|
static int
|
||||||
|
sum_histogram_values (unsigned char *data, guint8 threshold)
|
||||||
{
|
{
|
||||||
int r = 0;
|
int r = 0;
|
||||||
int i;
|
int i;
|
||||||
uint16_t *histogram = (uint16_t *)(data + 1);
|
guint16 *histogram = (guint16 *) (data + 1);
|
||||||
|
|
||||||
if (*data != 0xde)
|
if (*data != 0xde)
|
||||||
return -EILSEQ;
|
return -1;
|
||||||
|
|
||||||
if (threshold > 0x0f)
|
if (threshold > 0x0f)
|
||||||
return -EINVAL;
|
return -1;
|
||||||
|
|
||||||
/* FIXME endianness */
|
/* FIXME endianness */
|
||||||
for (i = threshold; i < 16; i++)
|
for (i = threshold; i < 16; i++)
|
||||||
@@ -280,76 +250,67 @@ static const struct aes_regwrite finger_det_reqs[] = {
|
|||||||
{ AES2501_REG_LPONT, AES2501_LPONT_MIN_VALUE },
|
{ AES2501_REG_LPONT, AES2501_LPONT_MIN_VALUE },
|
||||||
};
|
};
|
||||||
|
|
||||||
static void start_finger_detection(struct fp_img_dev *dev);
|
static void start_finger_detection (FpImageDevice *dev);
|
||||||
|
|
||||||
static void finger_det_data_cb(struct libusb_transfer *transfer)
|
static void
|
||||||
|
finger_det_data_cb (FpiUsbTransfer *transfer, FpDevice *_dev,
|
||||||
|
gpointer user_data, GError *error)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = transfer->user_data;
|
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
|
||||||
unsigned char *data = transfer->buffer;
|
unsigned char *data = transfer->buffer;
|
||||||
int i;
|
int i;
|
||||||
int sum = 0;
|
int sum = 0;
|
||||||
|
|
||||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
if (error)
|
||||||
fpi_imgdev_session_error(dev, -EIO);
|
{
|
||||||
goto out;
|
fpi_image_device_session_error (dev, error);
|
||||||
} else if (transfer->length != transfer->actual_length) {
|
return;
|
||||||
fpi_imgdev_session_error(dev, -EPROTO);
|
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* examine histogram to determine finger presence */
|
/* examine histogram to determine finger presence */
|
||||||
for (i = 1; i < 9; i++)
|
for (i = 1; i < 9; i++)
|
||||||
sum += (data[i] & 0xf) + (data[i] >> 4);
|
sum += (data[i] & 0xf) + (data[i] >> 4);
|
||||||
if (sum > 20) {
|
if (sum > 20)
|
||||||
|
{
|
||||||
/* finger present, start capturing */
|
/* finger present, start capturing */
|
||||||
fpi_imgdev_report_finger_status(dev, TRUE);
|
fpi_image_device_report_finger_status (dev, TRUE);
|
||||||
start_capture (dev);
|
start_capture (dev);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/* no finger, poll for a new histogram */
|
/* no finger, poll for a new histogram */
|
||||||
start_finger_detection (dev);
|
start_finger_detection (dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
|
||||||
g_free(data);
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void finger_det_reqs_cb(struct fp_img_dev *dev, int result,
|
static void
|
||||||
|
finger_det_reqs_cb (FpImageDevice *dev, GError *error,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
struct libusb_transfer *transfer;
|
FpiUsbTransfer *transfer;
|
||||||
unsigned char *data;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
if (result) {
|
if (error)
|
||||||
fpi_imgdev_session_error(dev, result);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
transfer = libusb_alloc_transfer(0);
|
|
||||||
if (!transfer) {
|
|
||||||
fpi_imgdev_session_error(dev, -ENOMEM);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
data = g_malloc(20);
|
|
||||||
libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), EP_IN, data, 20,
|
|
||||||
finger_det_data_cb, dev, BULK_TIMEOUT);
|
|
||||||
|
|
||||||
r = libusb_submit_transfer(transfer);
|
|
||||||
if (r < 0) {
|
|
||||||
g_free(data);
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
fpi_imgdev_session_error(dev, r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void start_finger_detection(struct fp_img_dev *dev)
|
|
||||||
{
|
{
|
||||||
struct aes2501_dev *aesdev = fpi_imgdev_get_user_data(dev);
|
fpi_image_device_session_error (dev, error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
|
||||||
|
transfer->short_is_error = TRUE;
|
||||||
|
fpi_usb_transfer_fill_bulk (transfer, EP_IN, FINGER_DETECTION_LEN);
|
||||||
|
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
||||||
|
finger_det_data_cb, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
start_finger_detection (FpImageDevice *dev)
|
||||||
|
{
|
||||||
|
FpiDeviceAes2501 *self = FPI_DEVICE_AES2501 (dev);
|
||||||
|
|
||||||
G_DEBUG_HERE ();
|
G_DEBUG_HERE ();
|
||||||
|
|
||||||
if (aesdev->deactivating) {
|
if (self->deactivating)
|
||||||
|
{
|
||||||
complete_deactivation (dev);
|
complete_deactivation (dev);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -420,7 +381,7 @@ static struct aes_regwrite strip_scan_reqs[] = {
|
|||||||
/* capture SM movement:
|
/* capture SM movement:
|
||||||
* write reqs and read data 1 + 2,
|
* write reqs and read data 1 + 2,
|
||||||
* request and read strip,
|
* request and read strip,
|
||||||
* jump back to request UNLESS theres no finger, in which case exit SM,
|
* jump back to request UNLESS there's no finger, in which case exit SM,
|
||||||
* report lack of finger presence, and move to finger detection */
|
* report lack of finger presence, and move to finger detection */
|
||||||
|
|
||||||
enum capture_states {
|
enum capture_states {
|
||||||
@@ -433,43 +394,50 @@ enum capture_states {
|
|||||||
CAPTURE_NUM_STATES,
|
CAPTURE_NUM_STATES,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void capture_read_strip_cb(struct libusb_transfer *transfer)
|
static void
|
||||||
|
capture_read_strip_cb (FpiUsbTransfer *transfer, FpDevice *_dev,
|
||||||
|
gpointer user_data, GError *error)
|
||||||
{
|
{
|
||||||
|
FpiSsm *ssm = transfer->ssm;
|
||||||
unsigned char *stripdata;
|
unsigned char *stripdata;
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
|
||||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
FpiDeviceAes2501 *self = FPI_DEVICE_AES2501 (_dev);
|
||||||
struct aes2501_dev *aesdev = fpi_imgdev_get_user_data(dev);
|
|
||||||
unsigned char *data = transfer->buffer;
|
unsigned char *data = transfer->buffer;
|
||||||
int sum;
|
int sum;
|
||||||
int threshold;
|
int threshold;
|
||||||
|
|
||||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
if (error)
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
{
|
||||||
goto out;
|
fpi_ssm_mark_failed (ssm, error);
|
||||||
} else if (transfer->length != transfer->actual_length) {
|
return;
|
||||||
fpi_ssm_mark_aborted(ssm, -EPROTO);
|
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
threshold = regval_from_dump (data + 1 + 192 * 8 + 1 + 16 * 2 + 1 + 8,
|
threshold = regval_from_dump (data + 1 + 192 * 8 + 1 + 16 * 2 + 1 + 8,
|
||||||
AES2501_REG_DATFMT);
|
AES2501_REG_DATFMT);
|
||||||
if (threshold < 0) {
|
if (threshold < 0)
|
||||||
fpi_ssm_mark_aborted(ssm, threshold);
|
{
|
||||||
goto out;
|
fpi_ssm_mark_failed (ssm,
|
||||||
|
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sum = sum_histogram_values (data + 1 + 192 * 8, threshold & 0x0f);
|
sum = sum_histogram_values (data + 1 + 192 * 8, threshold & 0x0f);
|
||||||
if (sum < 0) {
|
if (sum < 0)
|
||||||
fpi_ssm_mark_aborted(ssm, sum);
|
{
|
||||||
goto out;
|
fpi_ssm_mark_failed (ssm,
|
||||||
|
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
fp_dbg ("sum=%d", sum);
|
fp_dbg ("sum=%d", sum);
|
||||||
|
|
||||||
if (sum < AES2501_SUM_LOW_THRESH) {
|
if (sum < AES2501_SUM_LOW_THRESH)
|
||||||
|
{
|
||||||
strip_scan_reqs[4].value -= 0x8;
|
strip_scan_reqs[4].value -= 0x8;
|
||||||
if (strip_scan_reqs[4].value < AES2501_ADREFHI_MIN_VALUE)
|
if (strip_scan_reqs[4].value < AES2501_ADREFHI_MIN_VALUE)
|
||||||
strip_scan_reqs[4].value = AES2501_ADREFHI_MIN_VALUE;
|
strip_scan_reqs[4].value = AES2501_ADREFHI_MIN_VALUE;
|
||||||
} else if (sum > AES2501_SUM_HIGH_THRESH) {
|
}
|
||||||
|
else if (sum > AES2501_SUM_HIGH_THRESH)
|
||||||
|
{
|
||||||
strip_scan_reqs[4].value += 0x8;
|
strip_scan_reqs[4].value += 0x8;
|
||||||
if (strip_scan_reqs[4].value > AES2501_ADREFHI_MAX_VALUE)
|
if (strip_scan_reqs[4].value > AES2501_ADREFHI_MAX_VALUE)
|
||||||
strip_scan_reqs[4].value = AES2501_ADREFHI_MAX_VALUE;
|
strip_scan_reqs[4].value = AES2501_ADREFHI_MAX_VALUE;
|
||||||
@@ -479,28 +447,32 @@ static void capture_read_strip_cb(struct libusb_transfer *transfer)
|
|||||||
/* Sum is 0, maybe finger was removed? Wait for 3 empty frames
|
/* Sum is 0, maybe finger was removed? Wait for 3 empty frames
|
||||||
* to ensure
|
* to ensure
|
||||||
*/
|
*/
|
||||||
if (sum == 0) {
|
if (sum == 0)
|
||||||
aesdev->no_finger_cnt++;
|
{
|
||||||
if (aesdev->no_finger_cnt == 3) {
|
self->no_finger_cnt++;
|
||||||
struct fp_img *img;
|
if (self->no_finger_cnt == 3)
|
||||||
|
{
|
||||||
|
FpImage *img;
|
||||||
|
|
||||||
aesdev->strips = g_slist_reverse(aesdev->strips);
|
self->strips = g_slist_reverse (self->strips);
|
||||||
fpi_do_movement_estimation(&assembling_ctx,
|
fpi_do_movement_estimation (&assembling_ctx, self->strips);
|
||||||
aesdev->strips, aesdev->strips_len);
|
|
||||||
img = fpi_assemble_frames (&assembling_ctx,
|
img = fpi_assemble_frames (&assembling_ctx,
|
||||||
aesdev->strips, aesdev->strips_len);
|
self->strips);
|
||||||
img->flags |= FP_IMG_PARTIAL;
|
g_slist_free_full (self->strips, g_free);
|
||||||
g_slist_free_full(aesdev->strips, g_free);
|
self->strips = NULL;
|
||||||
aesdev->strips = NULL;
|
self->strips_len = 0;
|
||||||
aesdev->strips_len = 0;
|
fpi_image_device_image_captured (dev, img);
|
||||||
fpi_imgdev_image_captured(dev, img);
|
fpi_image_device_report_finger_status (dev, FALSE);
|
||||||
fpi_imgdev_report_finger_status(dev, FALSE);
|
|
||||||
/* marking machine complete will re-trigger finger detection loop */
|
/* marking machine complete will re-trigger finger detection loop */
|
||||||
fpi_ssm_mark_completed (ssm);
|
fpi_ssm_mark_completed (ssm);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
fpi_ssm_jump_to_state (ssm, CAPTURE_REQUEST_STRIP);
|
fpi_ssm_jump_to_state (ssm, CAPTURE_REQUEST_STRIP);
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/* obtain next strip */
|
/* obtain next strip */
|
||||||
/* FIXME: would preallocating strip buffers be a decent optimization? */
|
/* FIXME: would preallocating strip buffers be a decent optimization? */
|
||||||
struct fpi_frame *stripe = g_malloc (FRAME_WIDTH * FRAME_HEIGHT / 2 + sizeof (struct fpi_frame));
|
struct fpi_frame *stripe = g_malloc (FRAME_WIDTH * FRAME_HEIGHT / 2 + sizeof (struct fpi_frame));
|
||||||
@@ -508,100 +480,104 @@ static void capture_read_strip_cb(struct libusb_transfer *transfer)
|
|||||||
stripe->delta_y = 0;
|
stripe->delta_y = 0;
|
||||||
stripdata = stripe->data;
|
stripdata = stripe->data;
|
||||||
memcpy (stripdata, data + 1, 192 * 8);
|
memcpy (stripdata, data + 1, 192 * 8);
|
||||||
aesdev->no_finger_cnt = 0;
|
self->no_finger_cnt = 0;
|
||||||
aesdev->strips = g_slist_prepend(aesdev->strips, stripe);
|
self->strips = g_slist_prepend (self->strips, stripe);
|
||||||
aesdev->strips_len++;
|
self->strips_len++;
|
||||||
|
|
||||||
fpi_ssm_jump_to_state (ssm, CAPTURE_REQUEST_STRIP);
|
fpi_ssm_jump_to_state (ssm, CAPTURE_REQUEST_STRIP);
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
|
||||||
g_free(data);
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void capture_run_state(struct fpi_ssm *ssm)
|
static void
|
||||||
|
capture_run_state (FpiSsm *ssm, FpDevice *device)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
|
||||||
struct aes2501_dev *aesdev = fpi_imgdev_get_user_data(dev);
|
FpiDeviceAes2501 *self = FPI_DEVICE_AES2501 (device);
|
||||||
int r;
|
|
||||||
|
|
||||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
switch (fpi_ssm_get_cur_state (ssm))
|
||||||
|
{
|
||||||
case CAPTURE_WRITE_REQS_1:
|
case CAPTURE_WRITE_REQS_1:
|
||||||
aes_write_regv (dev, capture_reqs_1, G_N_ELEMENTS (capture_reqs_1),
|
aes_write_regv (dev, capture_reqs_1, G_N_ELEMENTS (capture_reqs_1),
|
||||||
generic_write_regv_cb, ssm);
|
generic_write_regv_cb, ssm);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CAPTURE_READ_DATA_1:
|
case CAPTURE_READ_DATA_1:
|
||||||
generic_read_ignore_data(ssm, 159);
|
generic_read_ignore_data (ssm, device, READ_REGS_RESP_LEN);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CAPTURE_WRITE_REQS_2:
|
case CAPTURE_WRITE_REQS_2:
|
||||||
aes_write_regv (dev, capture_reqs_2, G_N_ELEMENTS (capture_reqs_2),
|
aes_write_regv (dev, capture_reqs_2, G_N_ELEMENTS (capture_reqs_2),
|
||||||
generic_write_regv_cb, ssm);
|
generic_write_regv_cb, ssm);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CAPTURE_READ_DATA_2:
|
case CAPTURE_READ_DATA_2:
|
||||||
generic_read_ignore_data(ssm, 159);
|
generic_read_ignore_data (ssm, device, READ_REGS_RESP_LEN);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CAPTURE_REQUEST_STRIP:
|
case CAPTURE_REQUEST_STRIP:
|
||||||
if (aesdev->deactivating)
|
if (self->deactivating)
|
||||||
fpi_ssm_mark_completed (ssm);
|
fpi_ssm_mark_completed (ssm);
|
||||||
else
|
else
|
||||||
aes_write_regv (dev, strip_scan_reqs, G_N_ELEMENTS (strip_scan_reqs),
|
aes_write_regv (dev, strip_scan_reqs, G_N_ELEMENTS (strip_scan_reqs),
|
||||||
generic_write_regv_cb, ssm);
|
generic_write_regv_cb, ssm);
|
||||||
break;
|
break;
|
||||||
case CAPTURE_READ_STRIP: ;
|
|
||||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
|
||||||
unsigned char *data;
|
|
||||||
|
|
||||||
if (!transfer) {
|
case CAPTURE_READ_STRIP: {
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
FpiUsbTransfer *transfer;
|
||||||
|
|
||||||
|
transfer = fpi_usb_transfer_new (device);
|
||||||
|
transfer->ssm = ssm;
|
||||||
|
transfer->short_is_error = TRUE;
|
||||||
|
fpi_usb_transfer_fill_bulk (transfer, EP_IN, STRIP_CAPTURE_LEN);
|
||||||
|
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
||||||
|
capture_read_strip_cb, NULL);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
data = g_malloc(1705);
|
|
||||||
libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), EP_IN, data, 1705,
|
|
||||||
capture_read_strip_cb, ssm, BULK_TIMEOUT);
|
|
||||||
|
|
||||||
r = libusb_submit_transfer(transfer);
|
|
||||||
if (r < 0) {
|
|
||||||
g_free(data);
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
fpi_ssm_mark_aborted(ssm, r);
|
|
||||||
}
|
}
|
||||||
break;
|
;
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void capture_sm_complete(struct fpi_ssm *ssm)
|
static void
|
||||||
|
capture_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
|
||||||
struct aes2501_dev *aesdev = fpi_imgdev_get_user_data(dev);
|
FpiDeviceAes2501 *self = FPI_DEVICE_AES2501 (_dev);
|
||||||
|
|
||||||
G_DEBUG_HERE ();
|
G_DEBUG_HERE ();
|
||||||
if (aesdev->deactivating)
|
|
||||||
|
if (self->deactivating)
|
||||||
|
{
|
||||||
complete_deactivation (dev);
|
complete_deactivation (dev);
|
||||||
else if (fpi_ssm_get_error(ssm))
|
g_clear_pointer (&error, g_error_free);
|
||||||
fpi_imgdev_session_error(dev, fpi_ssm_get_error(ssm));
|
}
|
||||||
|
else if (error)
|
||||||
|
{
|
||||||
|
fpi_image_device_session_error (dev, error);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
start_finger_detection (dev);
|
start_finger_detection (dev);
|
||||||
fpi_ssm_free(ssm);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void start_capture(struct fp_img_dev *dev)
|
static void
|
||||||
|
start_capture (FpImageDevice *dev)
|
||||||
{
|
{
|
||||||
struct aes2501_dev *aesdev = fpi_imgdev_get_user_data(dev);
|
FpiDeviceAes2501 *self = FPI_DEVICE_AES2501 (dev);
|
||||||
struct fpi_ssm *ssm;
|
FpiSsm *ssm;
|
||||||
|
|
||||||
if (aesdev->deactivating) {
|
if (self->deactivating)
|
||||||
|
{
|
||||||
complete_deactivation (dev);
|
complete_deactivation (dev);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
aesdev->no_finger_cnt = 0;
|
self->no_finger_cnt = 0;
|
||||||
/* Reset gain */
|
/* Reset gain */
|
||||||
strip_scan_reqs[4].value = AES2501_ADREFHI_MAX_VALUE;
|
strip_scan_reqs[4].value = AES2501_ADREFHI_MAX_VALUE;
|
||||||
ssm = fpi_ssm_new(fpi_imgdev_get_dev(dev), capture_run_state, CAPTURE_NUM_STATES);
|
ssm = fpi_ssm_new (FP_DEVICE (dev), capture_run_state,
|
||||||
|
CAPTURE_NUM_STATES);
|
||||||
G_DEBUG_HERE ();
|
G_DEBUG_HERE ();
|
||||||
fpi_ssm_set_user_data(ssm, dev);
|
|
||||||
fpi_ssm_start (ssm, capture_sm_complete);
|
fpi_ssm_start (ssm, capture_sm_complete);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -710,36 +686,43 @@ enum activate_states {
|
|||||||
ACTIVATE_NUM_STATES,
|
ACTIVATE_NUM_STATES,
|
||||||
};
|
};
|
||||||
|
|
||||||
void activate_read_regs_cb(struct fp_img_dev *dev, int status,
|
static void
|
||||||
|
activate_read_regs_cb (FpImageDevice *dev, GError *error,
|
||||||
unsigned char *regs, void *user_data)
|
unsigned char *regs, void *user_data)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = user_data;
|
FpiSsm *ssm = user_data;
|
||||||
struct aes2501_dev *aesdev = fpi_imgdev_get_user_data(dev);
|
FpiDeviceAes2501 *self = FPI_DEVICE_AES2501 (dev);
|
||||||
|
|
||||||
if (status != 0) {
|
if (error)
|
||||||
fpi_ssm_mark_aborted(ssm, status);
|
{
|
||||||
} else {
|
fpi_ssm_mark_failed (ssm, error);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
fp_dbg ("reg 0xaf = %x", regs[0x5f]);
|
fp_dbg ("reg 0xaf = %x", regs[0x5f]);
|
||||||
if (regs[0x5f] != 0x6b || ++aesdev->read_regs_retry_count == 13)
|
if (regs[0x5f] != 0x6b || ++self->read_regs_retry_count == 13)
|
||||||
fpi_ssm_jump_to_state (ssm, WRITE_INIT_4);
|
fpi_ssm_jump_to_state (ssm, WRITE_INIT_4);
|
||||||
else
|
else
|
||||||
fpi_ssm_next_state (ssm);
|
fpi_ssm_next_state (ssm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void activate_init3_cb(struct fp_img_dev *dev, int result,
|
static void
|
||||||
|
activate_init3_cb (FpImageDevice *dev, GError *error,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = user_data;
|
FpiSsm *ssm = user_data;
|
||||||
if (result == 0)
|
|
||||||
|
if (!error)
|
||||||
fpi_ssm_jump_to_state (ssm, READ_REGS);
|
fpi_ssm_jump_to_state (ssm, READ_REGS);
|
||||||
else
|
else
|
||||||
fpi_ssm_mark_aborted(ssm, result);
|
fpi_ssm_mark_failed (ssm, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void activate_run_state(struct fpi_ssm *ssm)
|
static void
|
||||||
|
activate_run_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
|
||||||
|
|
||||||
/* This state machine isn't as linear as it may appear. After doing init1
|
/* This state machine isn't as linear as it may appear. After doing init1
|
||||||
* and init2 register configuration writes, we have to poll a register
|
* and init2 register configuration writes, we have to poll a register
|
||||||
@@ -760,30 +743,37 @@ static void activate_run_state(struct fpi_ssm *ssm)
|
|||||||
aes_write_regv(init_4);
|
aes_write_regv(init_4);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
switch (fpi_ssm_get_cur_state (ssm))
|
||||||
|
{
|
||||||
case WRITE_INIT_1:
|
case WRITE_INIT_1:
|
||||||
aes_write_regv (dev, init_1, G_N_ELEMENTS (init_1),
|
aes_write_regv (dev, init_1, G_N_ELEMENTS (init_1),
|
||||||
generic_write_regv_cb, ssm);
|
generic_write_regv_cb, ssm);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case READ_DATA_1:
|
case READ_DATA_1:
|
||||||
fp_dbg ("read data 1");
|
fp_dbg ("read data 1");
|
||||||
generic_read_ignore_data(ssm, 20);
|
generic_read_ignore_data (ssm, _dev, FINGER_DETECTION_LEN);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WRITE_INIT_2:
|
case WRITE_INIT_2:
|
||||||
aes_write_regv (dev, init_2, G_N_ELEMENTS (init_2),
|
aes_write_regv (dev, init_2, G_N_ELEMENTS (init_2),
|
||||||
generic_write_regv_cb, ssm);
|
generic_write_regv_cb, ssm);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case READ_REGS:
|
case READ_REGS:
|
||||||
read_regs (dev, activate_read_regs_cb, ssm);
|
read_regs (dev, activate_read_regs_cb, ssm);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WRITE_INIT_3:
|
case WRITE_INIT_3:
|
||||||
aes_write_regv (dev, init_3, G_N_ELEMENTS (init_3),
|
aes_write_regv (dev, init_3, G_N_ELEMENTS (init_3),
|
||||||
activate_init3_cb, ssm);
|
activate_init3_cb, ssm);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WRITE_INIT_4:
|
case WRITE_INIT_4:
|
||||||
aes_write_regv (dev, init_4, G_N_ELEMENTS (init_4),
|
aes_write_regv (dev, init_4, G_N_ELEMENTS (init_4),
|
||||||
generic_write_regv_cb, ssm);
|
generic_write_regv_cb, ssm);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WRITE_INIT_5:
|
case WRITE_INIT_5:
|
||||||
aes_write_regv (dev, init_5, G_N_ELEMENTS (init_5),
|
aes_write_regv (dev, init_5, G_N_ELEMENTS (init_5),
|
||||||
generic_write_regv_cb, ssm);
|
generic_write_regv_cb, ssm);
|
||||||
@@ -791,98 +781,101 @@ static void activate_run_state(struct fpi_ssm *ssm)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void activate_sm_complete(struct fpi_ssm *ssm)
|
static void
|
||||||
|
activate_sm_complete (FpiSsm *ssm, FpDevice *dev, GError *error)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
fpi_image_device_activate_complete (FP_IMAGE_DEVICE (dev), error);
|
||||||
fp_dbg("status %d", fpi_ssm_get_error(ssm));
|
|
||||||
fpi_imgdev_activate_complete(dev, fpi_ssm_get_error(ssm));
|
|
||||||
|
|
||||||
if (!fpi_ssm_get_error(ssm))
|
if (!error)
|
||||||
start_finger_detection(dev);
|
start_finger_detection (FP_IMAGE_DEVICE (dev));
|
||||||
fpi_ssm_free(ssm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
static void
|
||||||
|
dev_activate (FpImageDevice *dev)
|
||||||
{
|
{
|
||||||
struct aes2501_dev *aesdev = fpi_imgdev_get_user_data(dev);
|
FpiDeviceAes2501 *self = FPI_DEVICE_AES2501 (dev);
|
||||||
struct fpi_ssm *ssm = fpi_ssm_new(fpi_imgdev_get_dev(dev), activate_run_state,
|
FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), activate_run_state,
|
||||||
ACTIVATE_NUM_STATES);
|
ACTIVATE_NUM_STATES);
|
||||||
fpi_ssm_set_user_data(ssm, dev);
|
|
||||||
aesdev->read_regs_retry_count = 0;
|
self->read_regs_retry_count = 0;
|
||||||
fpi_ssm_start (ssm, activate_sm_complete);
|
fpi_ssm_start (ssm, activate_sm_complete);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dev_deactivate(struct fp_img_dev *dev)
|
static void
|
||||||
|
dev_deactivate (FpImageDevice *dev)
|
||||||
{
|
{
|
||||||
struct aes2501_dev *aesdev = fpi_imgdev_get_user_data(dev);
|
FpiDeviceAes2501 *self = FPI_DEVICE_AES2501 (dev);
|
||||||
|
|
||||||
/* FIXME: audit cancellation points, probably need more, specifically
|
/* FIXME: audit cancellation points, probably need more, specifically
|
||||||
* in error handling paths? */
|
* in error handling paths? */
|
||||||
aesdev->deactivating = TRUE;
|
self->deactivating = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void complete_deactivation(struct fp_img_dev *dev)
|
static void
|
||||||
|
complete_deactivation (FpImageDevice *dev)
|
||||||
{
|
{
|
||||||
struct aes2501_dev *aesdev = fpi_imgdev_get_user_data(dev);
|
FpiDeviceAes2501 *self = FPI_DEVICE_AES2501 (dev);
|
||||||
|
|
||||||
G_DEBUG_HERE ();
|
G_DEBUG_HERE ();
|
||||||
|
|
||||||
/* FIXME: if we're in the middle of a scan, we should cancel the scan.
|
/* FIXME: if we're in the middle of a scan, we should cancel the scan.
|
||||||
* maybe we can do this with a master reset, unconditionally? */
|
* maybe we can do this with a master reset, unconditionally? */
|
||||||
|
|
||||||
aesdev->deactivating = FALSE;
|
self->deactivating = FALSE;
|
||||||
g_slist_free(aesdev->strips);
|
g_slist_free (self->strips);
|
||||||
aesdev->strips = NULL;
|
self->strips = NULL;
|
||||||
aesdev->strips_len = 0;
|
self->strips_len = 0;
|
||||||
fpi_imgdev_deactivate_complete(dev);
|
fpi_image_device_deactivate_complete (dev, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
static void
|
||||||
|
dev_init (FpImageDevice *dev)
|
||||||
{
|
{
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
/* FIXME check endpoints */
|
/* FIXME check endpoints */
|
||||||
int r;
|
|
||||||
struct aes2501_dev *aesdev;
|
|
||||||
|
|
||||||
r = libusb_claim_interface(fpi_imgdev_get_usb_dev(dev), 0);
|
g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error);
|
||||||
if (r < 0) {
|
fpi_image_device_open_complete (dev, error);
|
||||||
fp_err("could not claim interface 0: %s", libusb_error_name(r));
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
aesdev = g_malloc0(sizeof(struct aes2501_dev));
|
static void
|
||||||
fpi_imgdev_set_user_data(dev, aesdev);
|
dev_deinit (FpImageDevice *dev)
|
||||||
fpi_imgdev_open_complete(dev, 0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dev_deinit(struct fp_img_dev *dev)
|
|
||||||
{
|
{
|
||||||
struct aes2501_dev *aesdev = fpi_imgdev_get_user_data(dev);
|
GError *error = NULL;
|
||||||
g_free(aesdev);
|
|
||||||
libusb_release_interface(fpi_imgdev_get_usb_dev(dev), 0);
|
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)),
|
||||||
fpi_imgdev_close_complete(dev);
|
0, 0, &error);
|
||||||
|
fpi_image_device_close_complete (dev, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct usb_id id_table[] = {
|
static const FpIdEntry id_table[] = {
|
||||||
{ .vendor = 0x08ff, .product = 0x2500 }, /* AES2500 */
|
{ .vid = 0x08ff, .pid = 0x2500, },/* AES2500 */
|
||||||
{ .vendor = 0x08ff, .product = 0x2580 }, /* AES2501 */
|
{ .vid = 0x08ff, .pid = 0x2580, },/* AES2501 */
|
||||||
{ 0, 0, 0, },
|
{ .vid = 0, .pid = 0, .driver_data = 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fp_img_driver aes2501_driver = {
|
static void
|
||||||
.driver = {
|
fpi_device_aes2501_init (FpiDeviceAes2501 *self)
|
||||||
.id = AES2501_ID,
|
{
|
||||||
.name = FP_COMPONENT,
|
}
|
||||||
.full_name = "AuthenTec AES2501",
|
static void
|
||||||
.id_table = id_table,
|
fpi_device_aes2501_class_init (FpiDeviceAes2501Class *klass)
|
||||||
.scan_type = FP_SCAN_TYPE_SWIPE,
|
{
|
||||||
},
|
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
|
||||||
.flags = 0,
|
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
|
||||||
.img_height = -1,
|
|
||||||
.img_width = IMAGE_WIDTH,
|
|
||||||
|
|
||||||
.open = dev_init,
|
dev_class->id = "aes2501";
|
||||||
.close = dev_deinit,
|
dev_class->full_name = "AuthenTec AES2501";
|
||||||
.activate = dev_activate,
|
dev_class->type = FP_DEVICE_TYPE_USB;
|
||||||
.deactivate = dev_deactivate,
|
dev_class->id_table = id_table;
|
||||||
};
|
dev_class->scan_type = FP_SCAN_TYPE_SWIPE;
|
||||||
|
|
||||||
|
img_class->img_open = dev_init;
|
||||||
|
img_class->img_close = dev_deinit;
|
||||||
|
img_class->activate = dev_activate;
|
||||||
|
img_class->deactivate = dev_deactivate;
|
||||||
|
|
||||||
|
img_class->img_width = IMAGE_WIDTH;
|
||||||
|
img_class->img_height = -1;
|
||||||
|
}
|
||||||
|
|||||||
@@ -19,8 +19,7 @@
|
|||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __AES2501_H
|
#pragma once
|
||||||
#define __AES2501_H
|
|
||||||
|
|
||||||
enum aes2501_regs {
|
enum aes2501_regs {
|
||||||
AES2501_REG_CTRL1 = 0x80,
|
AES2501_REG_CTRL1 = 0x80,
|
||||||
@@ -109,7 +108,7 @@ enum aes2501_mesure_drive {
|
|||||||
|
|
||||||
/* 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 {
|
||||||
@@ -172,5 +171,3 @@ enum aes2501_sensor_gain2 {
|
|||||||
|
|
||||||
#define AES2501_SUM_HIGH_THRESH 1000
|
#define AES2501_SUM_HIGH_THRESH 1000
|
||||||
#define AES2501_SUM_LOW_THRESH 700
|
#define AES2501_SUM_LOW_THRESH 700
|
||||||
|
|
||||||
#endif /* __AES2501_H */
|
|
||||||
|
|||||||
@@ -27,11 +27,11 @@
|
|||||||
#include "aes2550.h"
|
#include "aes2550.h"
|
||||||
#include "aeslib.h"
|
#include "aeslib.h"
|
||||||
|
|
||||||
static void start_capture(struct fp_img_dev *dev);
|
static void start_capture (FpImageDevice *dev);
|
||||||
static void complete_deactivation(struct fp_img_dev *dev);
|
static void complete_deactivation (FpImageDevice *dev);
|
||||||
|
|
||||||
#define EP_IN (1 | LIBUSB_ENDPOINT_IN)
|
#define EP_IN (1 | FPI_USB_ENDPOINT_IN)
|
||||||
#define EP_OUT (2 | LIBUSB_ENDPOINT_OUT)
|
#define EP_OUT (2 | FPI_USB_ENDPOINT_OUT)
|
||||||
#define BULK_TIMEOUT 4000
|
#define BULK_TIMEOUT 4000
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -51,12 +51,18 @@ static void complete_deactivation(struct fp_img_dev *dev);
|
|||||||
#define FRAME_SIZE (FRAME_WIDTH * FRAME_HEIGHT)
|
#define FRAME_SIZE (FRAME_WIDTH * FRAME_HEIGHT)
|
||||||
#define IMAGE_WIDTH (FRAME_WIDTH + (FRAME_WIDTH / 2))
|
#define IMAGE_WIDTH (FRAME_WIDTH + (FRAME_WIDTH / 2))
|
||||||
|
|
||||||
struct aes2550_dev {
|
struct _FpiDeviceAes2550
|
||||||
|
{
|
||||||
|
FpImageDevice parent;
|
||||||
|
|
||||||
GSList *strips;
|
GSList *strips;
|
||||||
size_t strips_len;
|
size_t strips_len;
|
||||||
gboolean deactivating;
|
gboolean deactivating;
|
||||||
int heartbeat_cnt;
|
int heartbeat_cnt;
|
||||||
};
|
};
|
||||||
|
G_DECLARE_FINAL_TYPE (FpiDeviceAes2550, fpi_device_aes2550, FPI, DEVICE_AES2550,
|
||||||
|
FpImageDevice);
|
||||||
|
G_DEFINE_TYPE (FpiDeviceAes2550, fpi_device_aes2550, FP_TYPE_IMAGE_DEVICE);
|
||||||
|
|
||||||
static struct fpi_frame_asmbl_ctx assembling_ctx = {
|
static struct fpi_frame_asmbl_ctx assembling_ctx = {
|
||||||
.frame_width = FRAME_WIDTH,
|
.frame_width = FRAME_WIDTH,
|
||||||
@@ -78,98 +84,78 @@ static unsigned char finger_det_reqs[] = {
|
|||||||
AES2550_CMD_RUN_FD,
|
AES2550_CMD_RUN_FD,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void start_finger_detection(struct fp_img_dev *dev);
|
static void start_finger_detection (FpImageDevice *dev);
|
||||||
|
|
||||||
static void finger_det_data_cb(struct libusb_transfer *transfer)
|
static void
|
||||||
|
finger_det_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
|
gpointer user_data, GError *error)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = transfer->user_data;
|
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
|
||||||
unsigned char *data = transfer->buffer;
|
unsigned char *data = transfer->buffer;
|
||||||
|
|
||||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
if (error)
|
||||||
fp_dbg("data transfer status %d\n", transfer->status);
|
{
|
||||||
fpi_imgdev_session_error(dev, -EIO);
|
fpi_image_device_session_error (FP_IMAGE_DEVICE (device), error);
|
||||||
goto out;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fp_dbg ("transfer completed, len: %.4x, data: %.2x %.2x",
|
fp_dbg ("transfer completed, len: %.4x, data: %.2x %.2x",
|
||||||
transfer->actual_length, (int)data[0], (int)data[1]);
|
(gint) transfer->actual_length, (int) data[0], (int) data[1]);
|
||||||
|
|
||||||
/* Check if we got 2 bytes, reg address 0x83 and its value */
|
/* Check if we got 2 bytes, reg address 0x83 and its value */
|
||||||
if ((transfer->actual_length >= 2) && (data[0] == 0x83) && (data[1] & AES2550_REG83_FINGER_PRESENT)) {
|
if ((transfer->actual_length >= 2) && (data[0] == 0x83) && (data[1] & AES2550_REG83_FINGER_PRESENT))
|
||||||
|
{
|
||||||
/* finger present, start capturing */
|
/* finger present, start capturing */
|
||||||
fpi_imgdev_report_finger_status(dev, TRUE);
|
fpi_image_device_report_finger_status (dev, TRUE);
|
||||||
start_capture (dev);
|
start_capture (dev);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/* no finger, poll for a new histogram */
|
/* no finger, poll for a new histogram */
|
||||||
start_finger_detection (dev);
|
start_finger_detection (dev);
|
||||||
}
|
}
|
||||||
out:
|
|
||||||
g_free(data);
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void finger_det_reqs_cb(struct libusb_transfer *t)
|
static void
|
||||||
|
finger_det_reqs_cb (FpiUsbTransfer *t, FpDevice *device,
|
||||||
|
gpointer user_data, GError *error)
|
||||||
{
|
{
|
||||||
struct libusb_transfer *transfer;
|
FpiUsbTransfer *transfer;
|
||||||
unsigned char *data;
|
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
|
||||||
int r;
|
|
||||||
struct fp_img_dev *dev = t->user_data;
|
|
||||||
|
|
||||||
if (t->status != LIBUSB_TRANSFER_COMPLETED) {
|
if (error)
|
||||||
fp_dbg("req transfer status %d\n", t->status);
|
{
|
||||||
fpi_imgdev_session_error(dev, -EIO);
|
fpi_image_device_session_error (dev, error);
|
||||||
goto exit_free_transfer;
|
return;
|
||||||
} else if (t->length != t->actual_length) {
|
|
||||||
fp_dbg("expected %d, got %d bytes", t->length, t->actual_length);
|
|
||||||
fpi_imgdev_session_error(dev, -EPROTO);
|
|
||||||
goto exit_free_transfer;
|
|
||||||
}
|
|
||||||
|
|
||||||
transfer = libusb_alloc_transfer(0);
|
|
||||||
if (!transfer) {
|
|
||||||
fpi_imgdev_session_error(dev, -ENOMEM);
|
|
||||||
goto exit_free_transfer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
transfer = fpi_usb_transfer_new (device);
|
||||||
/* 2 bytes of result */
|
/* 2 bytes of result */
|
||||||
data = g_malloc(AES2550_EP_IN_BUF_SIZE);
|
fpi_usb_transfer_fill_bulk (transfer, EP_IN, AES2550_EP_IN_BUF_SIZE);
|
||||||
libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), EP_IN, data, AES2550_EP_IN_BUF_SIZE,
|
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
||||||
finger_det_data_cb, dev, BULK_TIMEOUT);
|
finger_det_data_cb, NULL);
|
||||||
|
|
||||||
r = libusb_submit_transfer(transfer);
|
|
||||||
if (r < 0) {
|
|
||||||
g_free(data);
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
fpi_imgdev_session_error(dev, r);
|
|
||||||
}
|
|
||||||
exit_free_transfer:
|
|
||||||
libusb_free_transfer(t);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void start_finger_detection(struct fp_img_dev *dev)
|
static void
|
||||||
|
start_finger_detection (FpImageDevice *dev)
|
||||||
{
|
{
|
||||||
int r;
|
FpiDeviceAes2550 *self = FPI_DEVICE_AES2550 (dev);
|
||||||
struct aes2550_dev *aesdev = fpi_imgdev_get_user_data(dev);
|
FpiUsbTransfer *transfer;
|
||||||
struct libusb_transfer *transfer;
|
|
||||||
G_DEBUG_HERE ();
|
G_DEBUG_HERE ();
|
||||||
|
|
||||||
if (aesdev->deactivating) {
|
if (self->deactivating)
|
||||||
|
{
|
||||||
complete_deactivation (dev);
|
complete_deactivation (dev);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
transfer = libusb_alloc_transfer(0);
|
transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
|
||||||
if (!transfer) {
|
transfer->short_is_error = TRUE;
|
||||||
fpi_imgdev_session_error(dev, -ENOMEM);
|
fpi_usb_transfer_fill_bulk_full (transfer, EP_OUT, finger_det_reqs,
|
||||||
return;
|
sizeof (finger_det_reqs), NULL);
|
||||||
}
|
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
||||||
libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), EP_OUT, finger_det_reqs,
|
finger_det_reqs_cb, NULL);
|
||||||
sizeof(finger_det_reqs), finger_det_reqs_cb, dev, BULK_TIMEOUT);
|
|
||||||
r = libusb_submit_transfer(transfer);
|
|
||||||
if (r < 0) {
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
fpi_imgdev_session_error(dev, r);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/****** CAPTURE ******/
|
/****** CAPTURE ******/
|
||||||
@@ -200,221 +186,213 @@ enum capture_states {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* Returns number of processed bytes */
|
/* Returns number of processed bytes */
|
||||||
static int process_strip_data(struct fpi_ssm *ssm, unsigned char *data)
|
static gboolean
|
||||||
|
process_strip_data (FpiSsm *ssm, FpImageDevice *dev,
|
||||||
|
unsigned char *data)
|
||||||
{
|
{
|
||||||
unsigned char *stripdata;
|
unsigned char *stripdata;
|
||||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
FpiDeviceAes2550 *self = FPI_DEVICE_AES2550 (dev);
|
||||||
struct aes2550_dev *aesdev = fpi_imgdev_get_user_data(dev);
|
|
||||||
struct fpi_frame *stripe;
|
struct fpi_frame *stripe;
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
if (data[0] != AES2550_EDATA_MAGIC) {
|
if (data[0] != AES2550_EDATA_MAGIC)
|
||||||
|
{
|
||||||
fp_dbg ("Bogus magic: %.2x\n", (int) (data[0]));
|
fp_dbg ("Bogus magic: %.2x\n", (int) (data[0]));
|
||||||
return -EPROTO;
|
return FALSE;
|
||||||
}
|
}
|
||||||
len = data[1] * 256 + data[2];
|
len = data[1] * 256 + data[2];
|
||||||
if (len != (AES2550_STRIP_SIZE - 3)) {
|
if (len != (AES2550_STRIP_SIZE - 3))
|
||||||
fp_dbg ("Bogus frame len: %.4x\n", len);
|
fp_dbg ("Bogus frame len: %.4x\n", len);
|
||||||
}
|
stripe = g_malloc0 (FRAME_WIDTH * FRAME_HEIGHT / 2 + sizeof (struct fpi_frame)); /* 4 bits per pixel */
|
||||||
stripe = g_malloc(FRAME_WIDTH * FRAME_HEIGHT / 2 + sizeof(struct fpi_frame)); /* 4 bits per pixel */
|
|
||||||
stripe->delta_x = (int8_t) data[6];
|
stripe->delta_x = (int8_t) data[6];
|
||||||
stripe->delta_y = -(int8_t) data[7];
|
stripe->delta_y = -(int8_t) data[7];
|
||||||
stripdata = stripe->data;
|
stripdata = stripe->data;
|
||||||
memcpy (stripdata, data + 33, FRAME_WIDTH * FRAME_HEIGHT / 2);
|
memcpy (stripdata, data + 33, FRAME_WIDTH * FRAME_HEIGHT / 2);
|
||||||
aesdev->strips = g_slist_prepend(aesdev->strips, stripe);
|
self->strips = g_slist_prepend (self->strips, stripe);
|
||||||
aesdev->strips_len++;
|
self->strips_len++;
|
||||||
|
|
||||||
fp_dbg ("deltas: %dx%d", stripe->delta_x, stripe->delta_y);
|
fp_dbg ("deltas: %dx%d", stripe->delta_x, stripe->delta_y);
|
||||||
|
|
||||||
return 0;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void capture_reqs_cb(struct libusb_transfer *transfer)
|
static void
|
||||||
|
capture_set_idle_reqs_cb (FpiUsbTransfer *transfer,
|
||||||
|
FpDevice *device, gpointer user_data,
|
||||||
|
GError *error)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
|
||||||
|
FpiDeviceAes2550 *self = FPI_DEVICE_AES2550 (dev);
|
||||||
|
|
||||||
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
|
if (!error && self->strips_len)
|
||||||
(transfer->length == transfer->actual_length)) {
|
|
||||||
fpi_ssm_next_state(ssm);
|
|
||||||
} else {
|
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
|
||||||
}
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void capture_set_idle_reqs_cb(struct libusb_transfer *transfer)
|
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
FpImage *img;
|
||||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
|
||||||
struct aes2550_dev *aesdev = fpi_imgdev_get_user_data(dev);
|
|
||||||
|
|
||||||
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
|
self->strips = g_slist_reverse (self->strips);
|
||||||
(transfer->length == transfer->actual_length) &&
|
img = fpi_assemble_frames (&assembling_ctx, self->strips);
|
||||||
aesdev->strips_len) {
|
g_slist_free_full (self->strips, g_free);
|
||||||
struct fp_img *img;
|
self->strips = NULL;
|
||||||
|
self->strips_len = 0;
|
||||||
aesdev->strips = g_slist_reverse(aesdev->strips);
|
fpi_image_device_image_captured (dev, img);
|
||||||
img = fpi_assemble_frames(&assembling_ctx,
|
fpi_image_device_report_finger_status (dev, FALSE);
|
||||||
aesdev->strips, aesdev->strips_len);
|
|
||||||
img->flags |= FP_IMG_PARTIAL;
|
|
||||||
g_slist_free_full(aesdev->strips, g_free);
|
|
||||||
aesdev->strips = NULL;
|
|
||||||
aesdev->strips_len = 0;
|
|
||||||
fpi_imgdev_image_captured(dev, img);
|
|
||||||
fpi_imgdev_report_finger_status(dev, FALSE);
|
|
||||||
/* marking machine complete will re-trigger finger detection loop */
|
/* marking machine complete will re-trigger finger detection loop */
|
||||||
fpi_ssm_mark_completed(ssm);
|
fpi_ssm_mark_completed (transfer->ssm);
|
||||||
} else {
|
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
|
||||||
}
|
}
|
||||||
libusb_free_transfer(transfer);
|
else
|
||||||
}
|
|
||||||
|
|
||||||
static void capture_read_data_cb(struct libusb_transfer *transfer)
|
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
if (error)
|
||||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
fpi_ssm_mark_failed (transfer->ssm, error);
|
||||||
struct aes2550_dev *aesdev = fpi_imgdev_get_user_data(dev);
|
else
|
||||||
unsigned char *data = transfer->buffer;
|
fpi_ssm_mark_failed (transfer->ssm,
|
||||||
int r;
|
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
|
||||||
|
}
|
||||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
|
||||||
fp_dbg("request is not completed, %d", transfer->status);
|
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fp_dbg("request completed, len: %.4x", transfer->actual_length);
|
static void
|
||||||
|
capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
|
gpointer user_data, GError *error)
|
||||||
|
{
|
||||||
|
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
|
||||||
|
FpiDeviceAes2550 *self = FPI_DEVICE_AES2550 (dev);
|
||||||
|
unsigned char *data = transfer->buffer;
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
fpi_ssm_mark_failed (transfer->ssm, error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fp_dbg ("request completed, len: %.4x", (gint) transfer->actual_length);
|
||||||
if (transfer->actual_length >= 2)
|
if (transfer->actual_length >= 2)
|
||||||
fp_dbg ("data: %.2x %.2x", (int) data[0], (int) data[1]);
|
fp_dbg ("data: %.2x %.2x", (int) data[0], (int) data[1]);
|
||||||
|
|
||||||
switch (transfer->actual_length) {
|
switch (transfer->actual_length)
|
||||||
|
{
|
||||||
case AES2550_STRIP_SIZE:
|
case AES2550_STRIP_SIZE:
|
||||||
r = process_strip_data(ssm, data);
|
if (!process_strip_data (transfer->ssm, dev, data))
|
||||||
if (r < 0) {
|
{
|
||||||
fp_dbg("Processing strip data failed: %d", r);
|
fp_dbg ("Processing strip data failed");
|
||||||
fpi_ssm_mark_aborted(ssm, -EPROTO);
|
fpi_ssm_mark_failed (transfer->ssm,
|
||||||
goto out;
|
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
aesdev->heartbeat_cnt = 0;
|
self->heartbeat_cnt = 0;
|
||||||
fpi_ssm_jump_to_state(ssm, CAPTURE_READ_DATA);
|
fpi_ssm_jump_to_state (transfer->ssm, CAPTURE_READ_DATA);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AES2550_HEARTBEAT_SIZE:
|
case AES2550_HEARTBEAT_SIZE:
|
||||||
if (data[0] == AES2550_HEARTBEAT_MAGIC) {
|
if (data[0] == AES2550_HEARTBEAT_MAGIC)
|
||||||
|
{
|
||||||
/* No data for a long time => finger was removed or there's no movement */
|
/* No data for a long time => finger was removed or there's no movement */
|
||||||
aesdev->heartbeat_cnt++;
|
self->heartbeat_cnt++;
|
||||||
if (aesdev->heartbeat_cnt == 3) {
|
if (self->heartbeat_cnt == 3)
|
||||||
|
{
|
||||||
/* Got 3 heartbeat message, that's enough to consider that finger was removed,
|
/* Got 3 heartbeat message, that's enough to consider that finger was removed,
|
||||||
* assemble image and submit it to the library */
|
* assemble image and submit it to the library */
|
||||||
fp_dbg ("Got 3 heartbeats => finger removed");
|
fp_dbg ("Got 3 heartbeats => finger removed");
|
||||||
fpi_ssm_next_state(ssm);
|
fpi_ssm_next_state (transfer->ssm);
|
||||||
} else {
|
|
||||||
fpi_ssm_jump_to_state(ssm, CAPTURE_READ_DATA);
|
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fp_dbg("Short frame %d, skip", transfer->actual_length);
|
|
||||||
fpi_ssm_jump_to_state(ssm, CAPTURE_READ_DATA);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
out:
|
|
||||||
g_free(transfer->buffer);
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void capture_run_state(struct fpi_ssm *ssm)
|
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
fpi_ssm_jump_to_state (transfer->ssm,
|
||||||
int r;
|
CAPTURE_READ_DATA);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
default:
|
||||||
|
fp_dbg ("Short frame %d, skip",
|
||||||
|
(gint) transfer->actual_length);
|
||||||
|
fpi_ssm_jump_to_state (transfer->ssm, CAPTURE_READ_DATA);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
capture_run_state (FpiSsm *ssm, FpDevice *dev)
|
||||||
|
{
|
||||||
|
switch (fpi_ssm_get_cur_state (ssm))
|
||||||
|
{
|
||||||
case CAPTURE_WRITE_REQS:
|
case CAPTURE_WRITE_REQS:
|
||||||
{
|
{
|
||||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
|
||||||
if (!transfer) {
|
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
fpi_usb_transfer_fill_bulk_full (transfer, EP_OUT, capture_reqs,
|
||||||
return;
|
sizeof (capture_reqs), NULL);
|
||||||
}
|
transfer->ssm = ssm;
|
||||||
libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), EP_OUT, capture_reqs,
|
transfer->short_is_error = TRUE;
|
||||||
sizeof(capture_reqs), capture_reqs_cb, ssm, BULK_TIMEOUT);
|
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
||||||
r = libusb_submit_transfer(transfer);
|
fpi_ssm_usb_transfer_cb, NULL);
|
||||||
if (r < 0) {
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CAPTURE_READ_DATA:
|
case CAPTURE_READ_DATA:
|
||||||
{
|
{
|
||||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
|
||||||
unsigned char *data;
|
|
||||||
|
|
||||||
if (!transfer) {
|
fpi_usb_transfer_fill_bulk (transfer, EP_IN, AES2550_EP_IN_BUF_SIZE);
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
transfer->ssm = ssm;
|
||||||
break;
|
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
||||||
}
|
capture_read_data_cb, NULL);
|
||||||
|
|
||||||
data = g_malloc(AES2550_EP_IN_BUF_SIZE);
|
|
||||||
libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), EP_IN, data, AES2550_EP_IN_BUF_SIZE,
|
|
||||||
capture_read_data_cb, ssm, BULK_TIMEOUT);
|
|
||||||
|
|
||||||
r = libusb_submit_transfer(transfer);
|
|
||||||
if (r < 0) {
|
|
||||||
g_free(data);
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
fpi_ssm_mark_aborted(ssm, r);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CAPTURE_SET_IDLE:
|
case CAPTURE_SET_IDLE:
|
||||||
{
|
{
|
||||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
|
||||||
if (!transfer) {
|
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
fpi_usb_transfer_fill_bulk_full (transfer, EP_OUT,
|
||||||
return;
|
capture_set_idle_reqs,
|
||||||
}
|
sizeof (capture_set_idle_reqs),
|
||||||
libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), EP_OUT, capture_set_idle_reqs,
|
NULL);
|
||||||
sizeof(capture_set_idle_reqs), capture_set_idle_reqs_cb, ssm, BULK_TIMEOUT);
|
transfer->ssm = ssm;
|
||||||
r = libusb_submit_transfer(transfer);
|
transfer->short_is_error = TRUE;
|
||||||
if (r < 0) {
|
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
||||||
libusb_free_transfer(transfer);
|
capture_set_idle_reqs_cb, NULL);
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
};
|
}
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void capture_sm_complete(struct fpi_ssm *ssm)
|
static void
|
||||||
|
capture_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
FpiDeviceAes2550 *self = FPI_DEVICE_AES2550 (_dev);
|
||||||
struct aes2550_dev *aesdev = fpi_imgdev_get_user_data(dev);
|
FpImageDevice *dev = FP_IMAGE_DEVICE (self);
|
||||||
|
|
||||||
fp_dbg ("Capture completed");
|
fp_dbg ("Capture completed");
|
||||||
if (aesdev->deactivating)
|
|
||||||
|
if (self->deactivating)
|
||||||
|
{
|
||||||
complete_deactivation (dev);
|
complete_deactivation (dev);
|
||||||
else if (fpi_ssm_get_error(ssm))
|
g_clear_pointer (&error, g_error_free);
|
||||||
fpi_imgdev_session_error(dev, fpi_ssm_get_error(ssm));
|
}
|
||||||
|
else if (error)
|
||||||
|
{
|
||||||
|
fpi_image_device_session_error (dev, error);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
start_finger_detection (dev);
|
start_finger_detection (dev);
|
||||||
fpi_ssm_free(ssm);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void start_capture(struct fp_img_dev *dev)
|
static void
|
||||||
|
start_capture (FpImageDevice *dev)
|
||||||
{
|
{
|
||||||
struct aes2550_dev *aesdev = fpi_imgdev_get_user_data(dev);
|
FpiDeviceAes2550 *self = FPI_DEVICE_AES2550 (dev);
|
||||||
struct fpi_ssm *ssm;
|
FpiSsm *ssm;
|
||||||
|
|
||||||
if (aesdev->deactivating) {
|
if (self->deactivating)
|
||||||
|
{
|
||||||
complete_deactivation (dev);
|
complete_deactivation (dev);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
aesdev->heartbeat_cnt = 0;
|
self->heartbeat_cnt = 0;
|
||||||
ssm = fpi_ssm_new(fpi_imgdev_get_dev(dev), capture_run_state, CAPTURE_NUM_STATES);
|
ssm = fpi_ssm_new (FP_DEVICE (dev), capture_run_state, CAPTURE_NUM_STATES);
|
||||||
G_DEBUG_HERE ();
|
G_DEBUG_HERE ();
|
||||||
fpi_ssm_set_user_data(ssm, dev);
|
|
||||||
fpi_ssm_start (ssm, capture_sm_complete);
|
fpi_ssm_start (ssm, capture_sm_complete);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -442,218 +420,162 @@ enum activate_states {
|
|||||||
ACTIVATE_NUM_STATES,
|
ACTIVATE_NUM_STATES,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void init_reqs_cb(struct libusb_transfer *transfer)
|
|
||||||
{
|
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
|
||||||
|
|
||||||
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
|
|
||||||
(transfer->length == transfer->actual_length)) {
|
|
||||||
fpi_ssm_next_state(ssm);
|
|
||||||
} else {
|
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
|
||||||
}
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void init_read_data_cb(struct libusb_transfer *transfer)
|
|
||||||
{
|
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
|
||||||
|
|
||||||
if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
|
|
||||||
fpi_ssm_next_state(ssm);
|
|
||||||
} else {
|
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
|
||||||
}
|
|
||||||
g_free(transfer->buffer);
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* TODO: use calibration table, datasheet is rather terse on that
|
/* TODO: use calibration table, datasheet is rather terse on that
|
||||||
* need more info for implementaion */
|
* need more info for implementation */
|
||||||
static void calibrate_read_data_cb(struct libusb_transfer *transfer)
|
static void
|
||||||
|
calibrate_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
|
gpointer user_data, GError *error)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
fpi_ssm_usb_transfer_cb (transfer, device, user_data, error);
|
||||||
|
|
||||||
if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
|
|
||||||
fpi_ssm_next_state(ssm);
|
|
||||||
} else {
|
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
|
||||||
}
|
|
||||||
g_free(transfer->buffer);
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void activate_run_state(struct fpi_ssm *ssm)
|
static void
|
||||||
|
activate_run_state (FpiSsm *ssm, FpDevice *dev)
|
||||||
|
{
|
||||||
|
switch (fpi_ssm_get_cur_state (ssm))
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
|
||||||
int r;
|
|
||||||
|
|
||||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
|
||||||
case WRITE_INIT:
|
case WRITE_INIT:
|
||||||
{
|
{
|
||||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
|
||||||
if (!transfer) {
|
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
fpi_usb_transfer_fill_bulk_full (transfer, EP_OUT, init_reqs,
|
||||||
return;
|
sizeof (init_reqs), NULL);
|
||||||
}
|
transfer->ssm = ssm;
|
||||||
libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), EP_OUT, init_reqs,
|
transfer->short_is_error = TRUE;
|
||||||
sizeof(init_reqs), init_reqs_cb, ssm, BULK_TIMEOUT);
|
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
||||||
r = libusb_submit_transfer(transfer);
|
fpi_ssm_usb_transfer_cb, NULL);
|
||||||
if (r < 0) {
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case READ_DATA:
|
case READ_DATA:
|
||||||
{
|
{
|
||||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
|
||||||
unsigned char *data;
|
|
||||||
|
|
||||||
if (!transfer) {
|
fpi_usb_transfer_fill_bulk (transfer, EP_IN, AES2550_EP_IN_BUF_SIZE);
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
transfer->ssm = ssm;
|
||||||
break;
|
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
||||||
}
|
fpi_ssm_usb_transfer_cb, NULL);
|
||||||
|
|
||||||
data = g_malloc(AES2550_EP_IN_BUF_SIZE);
|
|
||||||
libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), EP_IN, data, AES2550_EP_IN_BUF_SIZE,
|
|
||||||
init_read_data_cb, ssm, BULK_TIMEOUT);
|
|
||||||
|
|
||||||
r = libusb_submit_transfer(transfer);
|
|
||||||
if (r < 0) {
|
|
||||||
g_free(data);
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
fpi_ssm_mark_aborted(ssm, r);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CALIBRATE:
|
case CALIBRATE:
|
||||||
{
|
{
|
||||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
|
||||||
if (!transfer) {
|
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
fpi_usb_transfer_fill_bulk_full (transfer, EP_OUT,
|
||||||
return;
|
calibrate_reqs,
|
||||||
}
|
sizeof (calibrate_reqs), NULL);
|
||||||
libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), EP_OUT, calibrate_reqs,
|
transfer->ssm = ssm;
|
||||||
sizeof(calibrate_reqs), init_reqs_cb, ssm, BULK_TIMEOUT);
|
transfer->short_is_error = TRUE;
|
||||||
r = libusb_submit_transfer(transfer);
|
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
||||||
if (r < 0) {
|
fpi_ssm_usb_transfer_cb, NULL);
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case READ_CALIB_TABLE:
|
case READ_CALIB_TABLE:
|
||||||
{
|
{
|
||||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
|
||||||
unsigned char *data;
|
|
||||||
|
|
||||||
if (!transfer) {
|
fpi_usb_transfer_fill_bulk (transfer, EP_IN, AES2550_EP_IN_BUF_SIZE);
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
transfer->ssm = ssm;
|
||||||
break;
|
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
||||||
}
|
calibrate_read_data_cb, NULL);
|
||||||
|
|
||||||
data = g_malloc(AES2550_EP_IN_BUF_SIZE);
|
|
||||||
libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), EP_IN, data, AES2550_EP_IN_BUF_SIZE,
|
|
||||||
calibrate_read_data_cb, ssm, BULK_TIMEOUT);
|
|
||||||
|
|
||||||
r = libusb_submit_transfer(transfer);
|
|
||||||
if (r < 0) {
|
|
||||||
g_free(data);
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
fpi_ssm_mark_aborted(ssm, r);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void activate_sm_complete(struct fpi_ssm *ssm)
|
static void
|
||||||
|
activate_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
|
||||||
fp_dbg("status %d", fpi_ssm_get_error(ssm));
|
|
||||||
fpi_imgdev_activate_complete(dev, fpi_ssm_get_error(ssm));
|
|
||||||
|
|
||||||
if (!fpi_ssm_get_error(ssm))
|
fpi_image_device_activate_complete (dev, error);
|
||||||
|
|
||||||
|
if (!error)
|
||||||
start_finger_detection (dev);
|
start_finger_detection (dev);
|
||||||
fpi_ssm_free(ssm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
static void
|
||||||
|
dev_activate (FpImageDevice *dev)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = fpi_ssm_new(fpi_imgdev_get_dev(dev), activate_run_state,
|
FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), activate_run_state,
|
||||||
ACTIVATE_NUM_STATES);
|
ACTIVATE_NUM_STATES);
|
||||||
fpi_ssm_set_user_data(ssm, dev);
|
|
||||||
fpi_ssm_start (ssm, activate_sm_complete);
|
fpi_ssm_start (ssm, activate_sm_complete);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dev_deactivate(struct fp_img_dev *dev)
|
static void
|
||||||
|
dev_deactivate (FpImageDevice *dev)
|
||||||
{
|
{
|
||||||
struct aes2550_dev *aesdev = fpi_imgdev_get_user_data(dev);
|
FpiDeviceAes2550 *self = FPI_DEVICE_AES2550 (dev);
|
||||||
|
|
||||||
aesdev->deactivating = TRUE;
|
self->deactivating = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void complete_deactivation(struct fp_img_dev *dev)
|
static void
|
||||||
|
complete_deactivation (FpImageDevice *dev)
|
||||||
{
|
{
|
||||||
struct aes2550_dev *aesdev = fpi_imgdev_get_user_data(dev);
|
FpiDeviceAes2550 *self = FPI_DEVICE_AES2550 (dev);
|
||||||
|
|
||||||
G_DEBUG_HERE ();
|
G_DEBUG_HERE ();
|
||||||
|
|
||||||
aesdev->deactivating = FALSE;
|
self->deactivating = FALSE;
|
||||||
g_slist_free(aesdev->strips);
|
g_slist_free (self->strips);
|
||||||
aesdev->strips = NULL;
|
self->strips = NULL;
|
||||||
aesdev->strips_len = 0;
|
self->strips_len = 0;
|
||||||
fpi_imgdev_deactivate_complete(dev);
|
fpi_image_device_deactivate_complete (dev, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
static void
|
||||||
|
dev_init (FpImageDevice *dev)
|
||||||
{
|
{
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
/* TODO check that device has endpoints we're using */
|
/* TODO check that device has endpoints we're using */
|
||||||
int r;
|
|
||||||
struct aes2550_dev *aes2550_dev;
|
|
||||||
|
|
||||||
r = libusb_claim_interface(fpi_imgdev_get_usb_dev(dev), 0);
|
g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error);
|
||||||
if (r < 0) {
|
|
||||||
fp_err("could not claim interface 0: %s", libusb_error_name(r));
|
fpi_image_device_open_complete (dev, error);
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
aes2550_dev = g_malloc0(sizeof(struct aes2550_dev));
|
static void
|
||||||
fpi_imgdev_set_user_data(dev, aes2550_dev);
|
dev_deinit (FpImageDevice *dev)
|
||||||
fpi_imgdev_open_complete(dev, 0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dev_deinit(struct fp_img_dev *dev)
|
|
||||||
{
|
{
|
||||||
struct aes2550_dev *aesdev;
|
GError *error = NULL;
|
||||||
aesdev = fpi_imgdev_get_user_data(dev);
|
|
||||||
g_free(aesdev);
|
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)),
|
||||||
libusb_release_interface(fpi_imgdev_get_usb_dev(dev), 0);
|
0, 0, &error);
|
||||||
fpi_imgdev_close_complete(dev);
|
fpi_image_device_close_complete (dev, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct usb_id id_table[] = {
|
static const FpIdEntry id_table[] = {
|
||||||
{ .vendor = 0x08ff, .product = 0x2550 }, /* AES2550 */
|
{ .vid = 0x08ff, .pid = 0x2550, },/* AES2550 */
|
||||||
{ .vendor = 0x08ff, .product = 0x2810 }, /* AES2810 */
|
{ .vid = 0x08ff, .pid = 0x2810, },/* AES2810 */
|
||||||
{ 0, 0, 0, },
|
{ .vid = 0, .pid = 0, .driver_data = 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fp_img_driver aes2550_driver = {
|
static void
|
||||||
.driver = {
|
fpi_device_aes2550_init (FpiDeviceAes2550 *self)
|
||||||
.id = AES2550_ID,
|
{
|
||||||
.name = FP_COMPONENT,
|
}
|
||||||
.full_name = "AuthenTec AES2550/AES2810",
|
static void
|
||||||
.id_table = id_table,
|
fpi_device_aes2550_class_init (FpiDeviceAes2550Class *klass)
|
||||||
.scan_type = FP_SCAN_TYPE_SWIPE,
|
{
|
||||||
},
|
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
|
||||||
.flags = 0,
|
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
|
||||||
.img_height = -1,
|
|
||||||
.img_width = FRAME_WIDTH + FRAME_WIDTH / 2,
|
|
||||||
|
|
||||||
.open = dev_init,
|
dev_class->id = "aes2550";
|
||||||
.close = dev_deinit,
|
dev_class->full_name = "AuthenTec AES2550/AES2810";
|
||||||
.activate = dev_activate,
|
dev_class->type = FP_DEVICE_TYPE_USB;
|
||||||
.deactivate = dev_deactivate,
|
dev_class->id_table = id_table;
|
||||||
};
|
dev_class->scan_type = FP_SCAN_TYPE_SWIPE;
|
||||||
|
|
||||||
|
img_class->img_open = dev_init;
|
||||||
|
img_class->img_close = dev_deinit;
|
||||||
|
img_class->activate = dev_activate;
|
||||||
|
img_class->deactivate = dev_deactivate;
|
||||||
|
|
||||||
|
img_class->img_width = FRAME_WIDTH + FRAME_WIDTH / 2;
|
||||||
|
img_class->img_height = -1;
|
||||||
|
}
|
||||||
|
|||||||
@@ -17,8 +17,7 @@
|
|||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __AES2550_H
|
#pragma once
|
||||||
#define __AES2550_H
|
|
||||||
|
|
||||||
/* Registers bits */
|
/* Registers bits */
|
||||||
|
|
||||||
@@ -110,5 +109,3 @@ enum aes2550_cmds {
|
|||||||
#define AES2550_HEARTBEAT_MAGIC 0xdb
|
#define AES2550_HEARTBEAT_MAGIC 0xdb
|
||||||
|
|
||||||
#define AES2550_EP_IN_BUF_SIZE 8192
|
#define AES2550_EP_IN_BUF_SIZE 8192
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -27,6 +27,14 @@
|
|||||||
#define FRAME_WIDTH 192
|
#define FRAME_WIDTH 192
|
||||||
#define IMAGE_WIDTH (FRAME_WIDTH + (FRAME_WIDTH / 2))
|
#define IMAGE_WIDTH (FRAME_WIDTH + (FRAME_WIDTH / 2))
|
||||||
|
|
||||||
|
struct _FpiDeviceAes2660
|
||||||
|
{
|
||||||
|
FpiDeviceAesX660 parent;
|
||||||
|
};
|
||||||
|
G_DECLARE_FINAL_TYPE (FpiDeviceAes2660, fpi_device_aes2660, FPI,
|
||||||
|
DEVICE_AES2660, FpiDeviceAesX660);
|
||||||
|
G_DEFINE_TYPE (FpiDeviceAes2660, fpi_device_aes2660, FPI_TYPE_DEVICE_AES_X660);
|
||||||
|
|
||||||
static struct fpi_frame_asmbl_ctx assembling_ctx = {
|
static struct fpi_frame_asmbl_ctx assembling_ctx = {
|
||||||
.frame_width = FRAME_WIDTH,
|
.frame_width = FRAME_WIDTH,
|
||||||
.frame_height = AESX660_FRAME_HEIGHT,
|
.frame_height = AESX660_FRAME_HEIGHT,
|
||||||
@@ -34,81 +42,56 @@ static struct fpi_frame_asmbl_ctx assembling_ctx = {
|
|||||||
.get_pixel = aes_get_pixel,
|
.get_pixel = aes_get_pixel,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
static const FpIdEntry id_table[] = {
|
||||||
{
|
{ .vid = 0x08ff, .pid = 0x2660, },
|
||||||
/* TODO check that device has endpoints we're using */
|
{ .vid = 0x08ff, .pid = 0x2680, },
|
||||||
int r;
|
{ .vid = 0x08ff, .pid = 0x2681, },
|
||||||
struct aesX660_dev *aesdev;
|
{ .vid = 0x08ff, .pid = 0x2682, },
|
||||||
|
{ .vid = 0x08ff, .pid = 0x2683, },
|
||||||
r = libusb_claim_interface(fpi_imgdev_get_usb_dev(dev), 0);
|
{ .vid = 0x08ff, .pid = 0x2684, },
|
||||||
if (r < 0) {
|
{ .vid = 0x08ff, .pid = 0x2685, },
|
||||||
fp_err("could not claim interface 0: %s", libusb_error_name(r));
|
{ .vid = 0x08ff, .pid = 0x2686, },
|
||||||
return r;
|
{ .vid = 0x08ff, .pid = 0x2687, },
|
||||||
}
|
{ .vid = 0x08ff, .pid = 0x2688, },
|
||||||
|
{ .vid = 0x08ff, .pid = 0x2689, },
|
||||||
aesdev = g_malloc0(sizeof(struct aesX660_dev));
|
{ .vid = 0x08ff, .pid = 0x268a, },
|
||||||
fpi_imgdev_set_user_data(dev, aesdev);
|
{ .vid = 0x08ff, .pid = 0x268b, },
|
||||||
aesdev->buffer = g_malloc0(AES2660_FRAME_SIZE + AESX660_HEADER_SIZE);
|
{ .vid = 0x08ff, .pid = 0x268c, },
|
||||||
/* No scaling for AES2660 */
|
{ .vid = 0x08ff, .pid = 0x268d, },
|
||||||
aesdev->init_seqs[0] = aes2660_init_1;
|
{ .vid = 0x08ff, .pid = 0x268e, },
|
||||||
aesdev->init_seqs_len[0] = G_N_ELEMENTS(aes2660_init_1);
|
{ .vid = 0x08ff, .pid = 0x268f, },
|
||||||
aesdev->init_seqs[1] = aes2660_init_2;
|
{ .vid = 0x08ff, .pid = 0x2691, },
|
||||||
aesdev->init_seqs_len[1] = G_N_ELEMENTS(aes2660_init_2);
|
{ .vid = 0, .pid = 0, .driver_data = 0 },
|
||||||
aesdev->start_imaging_cmd = (unsigned char *)aes2660_start_imaging_cmd;
|
|
||||||
aesdev->start_imaging_cmd_len = sizeof(aes2660_start_imaging_cmd);
|
|
||||||
aesdev->assembling_ctx = &assembling_ctx;
|
|
||||||
aesdev->extra_img_flags = FP_IMG_PARTIAL;
|
|
||||||
|
|
||||||
fpi_imgdev_open_complete(dev, 0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dev_deinit(struct fp_img_dev *dev)
|
|
||||||
{
|
|
||||||
struct aesX660_dev *aesdev;
|
|
||||||
aesdev = fpi_imgdev_get_user_data(dev);
|
|
||||||
g_free(aesdev->buffer);
|
|
||||||
g_free(aesdev);
|
|
||||||
libusb_release_interface(fpi_imgdev_get_usb_dev(dev), 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 void
|
||||||
.driver = {
|
fpi_device_aes2660_init (FpiDeviceAes2660 *self)
|
||||||
.id = AES2660_ID,
|
{
|
||||||
.name = FP_COMPONENT,
|
}
|
||||||
.full_name = "AuthenTec AES2660",
|
|
||||||
.id_table = id_table,
|
|
||||||
.scan_type = FP_SCAN_TYPE_SWIPE,
|
|
||||||
},
|
|
||||||
.flags = 0,
|
|
||||||
.img_height = -1,
|
|
||||||
.img_width = FRAME_WIDTH + FRAME_WIDTH / 2,
|
|
||||||
|
|
||||||
.open = dev_init,
|
static void
|
||||||
.close = dev_deinit,
|
fpi_device_aes2660_class_init (FpiDeviceAes2660Class *klass)
|
||||||
.activate = aesX660_dev_activate,
|
{
|
||||||
.deactivate = aesX660_dev_deactivate,
|
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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -17,8 +17,7 @@
|
|||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __AES2660_H
|
#pragma once
|
||||||
#define __AES2660_H
|
|
||||||
|
|
||||||
#define AES2660_FRAME_SIZE 0x354
|
#define AES2660_FRAME_SIZE 0x354
|
||||||
|
|
||||||
@@ -1960,5 +1959,3 @@ static const unsigned char aes2660_start_imaging_cmd[] = {
|
|||||||
0x55, 0x07, 0x00, 0x80, 0x42, 0x00, 0xbf, 0x00, 0x00, 0x18,
|
0x55, 0x07, 0x00, 0x80, 0x42, 0x00, 0xbf, 0x00, 0x00, 0x18,
|
||||||
0x49, 0x03, 0x00, 0x20, 0x08, 0xc8
|
0x49, 0x03, 0x00, 0x20, 0x08, 0xc8
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -29,8 +29,6 @@
|
|||||||
|
|
||||||
#define FP_COMPONENT "aes3500"
|
#define FP_COMPONENT "aes3500"
|
||||||
|
|
||||||
#include "drivers_api.h"
|
|
||||||
#include "aeslib.h"
|
|
||||||
#include "aes3k.h"
|
#include "aes3k.h"
|
||||||
|
|
||||||
#define DATA_BUFLEN 0x2089
|
#define DATA_BUFLEN 0x2089
|
||||||
@@ -117,67 +115,44 @@ static struct aes_regwrite init_reqs[] = {
|
|||||||
{ 0x81, 0x00 },
|
{ 0x81, 0x00 },
|
||||||
};
|
};
|
||||||
|
|
||||||
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
struct _FpiDeviceAes3500
|
||||||
{
|
{
|
||||||
int r;
|
FpiDeviceAes3k parent;
|
||||||
struct aes3k_dev *aesdev;
|
};
|
||||||
|
G_DECLARE_FINAL_TYPE (FpiDeviceAes3500, fpi_device_aes3500, FPI,
|
||||||
r = libusb_claim_interface(fpi_imgdev_get_usb_dev(dev), 0);
|
DEVICE_AES3500, FpiDeviceAes3k);
|
||||||
if (r < 0) {
|
G_DEFINE_TYPE (FpiDeviceAes3500, fpi_device_aes3500, FPI_TYPE_DEVICE_AES3K);
|
||||||
fp_err("could not claim interface 0: %s", libusb_error_name(r));
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
aesdev = g_malloc0(sizeof(struct aes3k_dev));
|
|
||||||
fpi_imgdev_set_user_data(dev, aesdev);
|
|
||||||
|
|
||||||
if (!aesdev)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
aesdev->data_buflen = DATA_BUFLEN;
|
|
||||||
aesdev->frame_width = FRAME_WIDTH;
|
|
||||||
aesdev->frame_size = FRAME_SIZE;
|
|
||||||
aesdev->frame_number = FRAME_NUMBER;
|
|
||||||
aesdev->enlarge_factor = ENLARGE_FACTOR;
|
|
||||||
aesdev->init_reqs = init_reqs;
|
|
||||||
aesdev->init_reqs_len = G_N_ELEMENTS(init_reqs);
|
|
||||||
fpi_imgdev_open_complete(dev, 0);
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dev_deinit(struct fp_img_dev *dev)
|
|
||||||
{
|
|
||||||
struct aes3k_dev *aesdev = fpi_imgdev_get_user_data(dev);
|
|
||||||
g_free(aesdev);
|
|
||||||
libusb_release_interface(fpi_imgdev_get_usb_dev(dev), 0);
|
|
||||||
fpi_imgdev_close_complete(dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static const struct usb_id id_table[] = {
|
static const FpIdEntry id_table[] = {
|
||||||
{ .vendor = 0x08ff, .product = 0x5731 },
|
{ .vid = 0x08ff, .pid = 0x5731 },
|
||||||
{ 0, 0, 0, },
|
{ .vid = 0, .pid = 0, .driver_data = 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fp_img_driver aes3500_driver = {
|
static void
|
||||||
.driver = {
|
fpi_device_aes3500_init (FpiDeviceAes3500 *self)
|
||||||
.id = AES3500_ID,
|
{
|
||||||
.name = FP_COMPONENT,
|
}
|
||||||
.full_name = "AuthenTec AES3500",
|
|
||||||
.id_table = id_table,
|
|
||||||
.scan_type = FP_SCAN_TYPE_PRESS,
|
|
||||||
},
|
|
||||||
.flags = 0,
|
|
||||||
.img_height = FRAME_WIDTH * ENLARGE_FACTOR,
|
|
||||||
.img_width = FRAME_WIDTH * ENLARGE_FACTOR,
|
|
||||||
|
|
||||||
/* temporarily lowered until image quality improves */
|
static void
|
||||||
.bz3_threshold = 9,
|
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);
|
||||||
|
|
||||||
.open = dev_init,
|
dev_class->id = "aes3500";
|
||||||
.close = dev_deinit,
|
dev_class->full_name = "AuthenTec AES3500";
|
||||||
.activate = aes3k_dev_activate,
|
dev_class->id_table = id_table;
|
||||||
.deactivate = aes3k_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);
|
||||||
|
}
|
||||||
|
|||||||
@@ -40,19 +40,30 @@
|
|||||||
#include "aeslib.h"
|
#include "aeslib.h"
|
||||||
#include "aes3k.h"
|
#include "aes3k.h"
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
FpiUsbTransfer *img_trf;
|
||||||
|
gboolean deactivating;
|
||||||
|
} FpiDeviceAes3kPrivate;
|
||||||
|
|
||||||
#define CTRL_TIMEOUT 1000
|
#define CTRL_TIMEOUT 1000
|
||||||
#define EP_IN (1 | LIBUSB_ENDPOINT_IN)
|
#define EP_IN (1 | FPI_USB_ENDPOINT_IN)
|
||||||
#define EP_OUT (2 | LIBUSB_ENDPOINT_OUT)
|
#define EP_OUT (2 | FPI_USB_ENDPOINT_OUT)
|
||||||
|
|
||||||
static void do_capture(struct fp_img_dev *dev);
|
static void do_capture (FpImageDevice *dev);
|
||||||
|
|
||||||
static void aes3k_assemble_image(unsigned char *input, size_t width, size_t height,
|
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)
|
unsigned char *output)
|
||||||
{
|
{
|
||||||
size_t row, column;
|
size_t row, column;
|
||||||
|
|
||||||
for (column = 0; column < width; column++) {
|
for (column = 0; column < width; column++)
|
||||||
for (row = 0; row < height; row += 2) {
|
{
|
||||||
|
for (row = 0; row < height; row += 2)
|
||||||
|
{
|
||||||
output[width * row + column] = (*input & 0x0f) * 17;
|
output[width * row + column] = (*input & 0x0f) * 17;
|
||||||
output[width * (row + 1) + column] = ((*input & 0xf0) >> 4) * 17;
|
output[width * (row + 1) + column] = ((*input & 0xf0) >> 4) * 17;
|
||||||
input++;
|
input++;
|
||||||
@@ -60,104 +71,156 @@ static void aes3k_assemble_image(unsigned char *input, size_t width, size_t heig
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void img_cb(struct libusb_transfer *transfer)
|
static void
|
||||||
|
img_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
|
gpointer user_data, GError *error)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = transfer->user_data;
|
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
|
||||||
struct aes3k_dev *aesdev = fpi_imgdev_get_user_data(dev);
|
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;
|
unsigned char *ptr = transfer->buffer;
|
||||||
struct fp_img *tmp;
|
FpImage *tmp;
|
||||||
struct fp_img *img;
|
FpImage *img;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (transfer->status == LIBUSB_TRANSFER_CANCELLED) {
|
priv->img_trf = NULL;
|
||||||
goto err;
|
|
||||||
} else if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
if (error)
|
||||||
fpi_imgdev_session_error(dev, -EIO);
|
{
|
||||||
goto err;
|
if (g_error_matches (error,
|
||||||
} else if (transfer->length != transfer->actual_length) {
|
G_IO_ERROR,
|
||||||
fpi_imgdev_session_error(dev, -EPROTO);
|
G_IO_ERROR_CANCELLED))
|
||||||
goto err;
|
{
|
||||||
|
/* Deactivation was completed. */
|
||||||
|
g_error_free (error);
|
||||||
|
if (priv->deactivating)
|
||||||
|
fpi_image_device_deactivate_complete (dev, NULL);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fpi_imgdev_report_finger_status(dev, TRUE);
|
fpi_image_device_session_error (dev, error);
|
||||||
|
}
|
||||||
|
|
||||||
tmp = fpi_img_new(aesdev->frame_width * aesdev->frame_width);
|
fpi_image_device_report_finger_status (dev, TRUE);
|
||||||
tmp->width = aesdev->frame_width;
|
|
||||||
tmp->height = aesdev->frame_width;
|
tmp = fp_image_new (cls->frame_width, cls->frame_width);
|
||||||
tmp->flags = FP_IMG_COLORS_INVERTED | FP_IMG_V_FLIPPED | FP_IMG_H_FLIPPED;
|
tmp->width = cls->frame_width;
|
||||||
for (i = 0; i < aesdev->frame_number; i++) {
|
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);
|
fp_dbg ("frame header byte %02x", *ptr);
|
||||||
ptr++;
|
ptr++;
|
||||||
aes3k_assemble_image(ptr, aesdev->frame_width, AES3K_FRAME_HEIGHT, tmp->data + (i * aesdev->frame_width * AES3K_FRAME_HEIGHT));
|
aes3k_assemble_image (ptr, cls->frame_width, AES3K_FRAME_HEIGHT, tmp->data + (i * cls->frame_width * AES3K_FRAME_HEIGHT));
|
||||||
ptr += aesdev->frame_size;
|
ptr += cls->frame_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME: this is an ugly hack to make the image big enough for NBIS
|
/* FIXME: this is an ugly hack to make the image big enough for NBIS
|
||||||
* to process reliably */
|
* to process reliably */
|
||||||
img = fpi_im_resize(tmp, aesdev->enlarge_factor, aesdev->enlarge_factor);
|
img = fpi_image_resize (tmp, cls->enlarge_factor, cls->enlarge_factor);
|
||||||
fp_img_free(tmp);
|
g_object_unref (tmp);
|
||||||
fpi_imgdev_image_captured(dev, img);
|
fpi_image_device_image_captured (dev, img);
|
||||||
|
|
||||||
/* FIXME: rather than assuming finger has gone, we should poll regs until
|
/* FIXME: rather than assuming finger has gone, we should poll regs until
|
||||||
* it really has, then restart the capture */
|
* it really has, then restart the capture */
|
||||||
fpi_imgdev_report_finger_status(dev, FALSE);
|
fpi_image_device_report_finger_status (dev, FALSE);
|
||||||
|
|
||||||
do_capture (dev);
|
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)
|
static void
|
||||||
|
do_capture (FpImageDevice *dev)
|
||||||
{
|
{
|
||||||
struct aes3k_dev *aesdev = fpi_imgdev_get_user_data(dev);
|
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
|
||||||
unsigned char *data;
|
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self);
|
||||||
int r;
|
FpiDeviceAes3kClass *cls = FPI_DEVICE_AES3K_GET_CLASS (self);
|
||||||
|
|
||||||
aesdev->img_trf = libusb_alloc_transfer(0);
|
priv->img_trf = fpi_usb_transfer_new (FP_DEVICE (dev));
|
||||||
if (!aesdev->img_trf) {
|
fpi_usb_transfer_fill_bulk (priv->img_trf, EP_IN, cls->data_buflen);
|
||||||
fpi_imgdev_session_error(dev, -EIO);
|
priv->img_trf->short_is_error = TRUE;
|
||||||
|
fpi_usb_transfer_submit (priv->img_trf, 0,
|
||||||
|
fpi_device_get_cancellable (FP_DEVICE (dev)),
|
||||||
|
img_cb, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
init_reqs_cb (FpImageDevice *dev, GError *result, void *user_data)
|
||||||
|
{
|
||||||
|
fpi_image_device_activate_complete (dev, result);
|
||||||
|
if (!result)
|
||||||
|
do_capture (dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
aes3k_dev_activate (FpImageDevice *dev)
|
||||||
|
{
|
||||||
|
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
|
||||||
|
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self);
|
||||||
|
FpiDeviceAes3kClass *cls = FPI_DEVICE_AES3K_GET_CLASS (self);
|
||||||
|
|
||||||
|
priv->deactivating = FALSE;
|
||||||
|
aes_write_regv (dev, cls->init_reqs, cls->init_reqs_len, init_reqs_cb, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
aes3k_dev_deactivate (FpImageDevice *dev)
|
||||||
|
{
|
||||||
|
FpiDeviceAes3k *self = FPI_DEVICE_AES3K (dev);
|
||||||
|
FpiDeviceAes3kPrivate *priv = fpi_device_aes3k_get_instance_private (self);
|
||||||
|
|
||||||
|
priv->deactivating = TRUE;
|
||||||
|
if (priv->img_trf)
|
||||||
|
return;
|
||||||
|
fpi_image_device_deactivate_complete (dev, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
data = g_malloc(aesdev->data_buflen);
|
fpi_image_device_open_complete (dev, NULL);
|
||||||
libusb_fill_bulk_transfer(aesdev->img_trf, fpi_imgdev_get_usb_dev(dev), EP_IN, data,
|
|
||||||
aesdev->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)
|
static void
|
||||||
|
aes3k_dev_deinit (FpImageDevice *dev)
|
||||||
{
|
{
|
||||||
fpi_imgdev_activate_complete(dev, result);
|
GError *error = NULL;
|
||||||
if (result == 0)
|
|
||||||
do_capture(dev);
|
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)),
|
||||||
|
0, 0, &error);
|
||||||
|
fpi_image_device_close_complete (dev, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
int aes3k_dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
|
||||||
|
static void
|
||||||
|
fpi_device_aes3k_class_init (FpiDeviceAes3kClass *klass)
|
||||||
{
|
{
|
||||||
struct aes3k_dev *aesdev = fpi_imgdev_get_user_data(dev);
|
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
|
||||||
aes_write_regv(dev, aesdev->init_reqs, aesdev->init_reqs_len, init_reqs_cb, NULL);
|
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
|
||||||
return 0;
|
|
||||||
|
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->deactivate = aes3k_dev_deactivate;
|
||||||
|
|
||||||
|
/* Extremely low due to low image quality. */
|
||||||
|
img_class->bz3_threshold = 9;
|
||||||
|
|
||||||
|
/* Everything else is set by the subclasses. */
|
||||||
}
|
}
|
||||||
|
|
||||||
void aes3k_dev_deactivate(struct fp_img_dev *dev)
|
|
||||||
{
|
|
||||||
struct aes3k_dev *aesdev = fpi_imgdev_get_user_data(dev);
|
|
||||||
|
|
||||||
/* 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
@@ -34,25 +34,27 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __AES3K_H
|
#pragma once
|
||||||
#define __AES3K_H
|
#include "fpi-image-device.h"
|
||||||
|
#include "aeslib.h"
|
||||||
|
|
||||||
#define AES3K_FRAME_HEIGHT 16
|
#define AES3K_FRAME_HEIGHT 16
|
||||||
|
|
||||||
struct aes3k_dev {
|
G_DECLARE_DERIVABLE_TYPE (FpiDeviceAes3k, fpi_device_aes3k, FPI,
|
||||||
struct libusb_transfer *img_trf;
|
DEVICE_AES3K, FpImageDevice)
|
||||||
size_t frame_width; /* image size = frame_width x frame_width */
|
|
||||||
size_t frame_size; /* 4 bits/pixel: frame_width x AES3K_FRAME_HEIGHT / 2 */
|
|
||||||
size_t frame_number; /* number of frames */
|
|
||||||
size_t enlarge_factor;
|
|
||||||
|
|
||||||
size_t data_buflen; /* buffer length of usb bulk transfer */
|
#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 */
|
struct aes_regwrite *init_reqs; /* initial values sent to device */
|
||||||
size_t init_reqs_len;
|
gsize init_reqs_len;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
int aes3k_dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state);
|
|
||||||
void aes3k_dev_deactivate(struct fp_img_dev *dev);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -26,8 +26,6 @@
|
|||||||
|
|
||||||
#define FP_COMPONENT "aes4000"
|
#define FP_COMPONENT "aes4000"
|
||||||
|
|
||||||
#include "drivers_api.h"
|
|
||||||
#include "aeslib.h"
|
|
||||||
#include "aes3k.h"
|
#include "aes3k.h"
|
||||||
|
|
||||||
#define DATA_BUFLEN 0x1259
|
#define DATA_BUFLEN 0x1259
|
||||||
@@ -114,67 +112,44 @@ static struct aes_regwrite init_reqs[] = {
|
|||||||
{ 0x81, 0x00 },
|
{ 0x81, 0x00 },
|
||||||
};
|
};
|
||||||
|
|
||||||
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
struct _FpiDeviceAes4000
|
||||||
{
|
{
|
||||||
int r;
|
FpiDeviceAes3k parent;
|
||||||
struct aes3k_dev *aesdev;
|
};
|
||||||
|
G_DECLARE_FINAL_TYPE (FpiDeviceAes4000, fpi_device_aes4000, FPI,
|
||||||
r = libusb_claim_interface(fpi_imgdev_get_usb_dev(dev), 0);
|
DEVICE_AES4000, FpiDeviceAes3k);
|
||||||
if (r < 0) {
|
G_DEFINE_TYPE (FpiDeviceAes4000, fpi_device_aes4000, FPI_TYPE_DEVICE_AES3K);
|
||||||
fp_err("could not claim interface 0: %s", libusb_error_name(r));
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
aesdev = g_malloc0(sizeof(struct aes3k_dev));
|
|
||||||
fpi_imgdev_set_user_data(dev, aesdev);
|
|
||||||
|
|
||||||
if (!aesdev)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
aesdev->data_buflen = DATA_BUFLEN;
|
|
||||||
aesdev->frame_width = FRAME_WIDTH;
|
|
||||||
aesdev->frame_size = FRAME_SIZE;
|
|
||||||
aesdev->frame_number = FRAME_NUMBER;
|
|
||||||
aesdev->enlarge_factor = ENLARGE_FACTOR;
|
|
||||||
aesdev->init_reqs = init_reqs;
|
|
||||||
aesdev->init_reqs_len = G_N_ELEMENTS(init_reqs);
|
|
||||||
fpi_imgdev_open_complete(dev, 0);
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dev_deinit(struct fp_img_dev *dev)
|
|
||||||
{
|
|
||||||
struct aes3k_dev *aesdev = fpi_imgdev_get_user_data(dev);
|
|
||||||
g_free(aesdev);
|
|
||||||
libusb_release_interface(fpi_imgdev_get_usb_dev(dev), 0);
|
|
||||||
fpi_imgdev_close_complete(dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static const struct usb_id id_table[] = {
|
static const FpIdEntry id_table[] = {
|
||||||
{ .vendor = 0x08ff, .product = 0x5501 },
|
{ .pid = 0x08ff, .vid = 0x5501 },
|
||||||
{ 0, 0, 0, },
|
{ .vid = 0, .pid = 0, .driver_data = 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 = FRAME_WIDTH * ENLARGE_FACTOR,
|
|
||||||
.img_width = FRAME_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 = aes3k_dev_activate,
|
dev_class->id_table = id_table;
|
||||||
.deactivate = aes3k_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);
|
||||||
|
}
|
||||||
|
|||||||
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,8 +17,7 @@
|
|||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __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
|
||||||
@@ -43,37 +42,32 @@
|
|||||||
|
|
||||||
#define AESX660_FRAME_HEIGHT 8
|
#define AESX660_FRAME_HEIGHT 8
|
||||||
|
|
||||||
struct aesX660_dev {
|
G_DECLARE_DERIVABLE_TYPE (FpiDeviceAesX660, fpi_device_aes_x660, FPI,
|
||||||
GSList *strips;
|
DEVICE_AES_X660, FpImageDevice)
|
||||||
size_t strips_len;
|
|
||||||
gboolean deactivating;
|
#define FPI_TYPE_DEVICE_AES_X660 (fpi_device_aes_x660_get_type ())
|
||||||
struct aesX660_cmd *init_seq;
|
|
||||||
size_t init_seq_len;
|
struct _FpiDeviceAesX660Class
|
||||||
unsigned int init_cmd_idx;
|
{
|
||||||
unsigned int init_seq_idx;
|
FpImageDeviceClass parent;
|
||||||
struct libusb_transfer *fd_data_transfer;
|
|
||||||
unsigned char *buffer;
|
|
||||||
size_t buffer_size;
|
|
||||||
size_t buffer_max;
|
|
||||||
|
|
||||||
/* Device-specific stuff */
|
|
||||||
struct aesX660_cmd *init_seqs[2];
|
struct aesX660_cmd *init_seqs[2];
|
||||||
size_t init_seqs_len[2];
|
gsize init_seqs_len[2];
|
||||||
unsigned char *start_imaging_cmd;
|
guint8 *start_imaging_cmd;
|
||||||
size_t start_imaging_cmd_len;
|
gsize start_imaging_cmd_len;
|
||||||
struct fpi_frame_asmbl_ctx *assembling_ctx;
|
struct fpi_frame_asmbl_ctx *assembling_ctx;
|
||||||
uint16_t extra_img_flags;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
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,
|
||||||
@@ -83,40 +77,35 @@ static const unsigned char led_blink_cmd[] = {
|
|||||||
|
|
||||||
/* 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
|
|
||||||
|
|||||||
@@ -18,159 +18,208 @@
|
|||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __ELAN_H
|
#pragma once
|
||||||
#define __ELAN_H
|
|
||||||
|
|
||||||
#include <string.h>
|
#include <glib.h>
|
||||||
#include <libusb.h>
|
|
||||||
|
|
||||||
/* number of pixels to discard on left and right (along raw image height)
|
#define ELAN_VEND_ID 0x04f3
|
||||||
* because they have different intensity from the rest of the frame */
|
|
||||||
#define ELAN_FRAME_MARGIN 12
|
/* 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 */
|
/* min and max frames in a capture */
|
||||||
#define ELAN_MIN_FRAMES 7
|
#define ELAN_MIN_FRAMES 7
|
||||||
#define ELAN_MAX_FRAMES 30
|
#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
|
/* number of frames to drop at the end of capture because frames captured
|
||||||
* while the finger is being lifted can be bad */
|
* while the finger is being lifted can be bad */
|
||||||
#define ELAN_SKIP_LAST_FRAMES 1
|
#define ELAN_SKIP_LAST_FRAMES 2
|
||||||
|
|
||||||
#define ELAN_CMD_LEN 0x2
|
#define ELAN_CMD_LEN 0x2
|
||||||
#define ELAN_EP_CMD_OUT (0x1 | LIBUSB_ENDPOINT_OUT)
|
#define ELAN_EP_CMD_OUT (0x1 | FPI_USB_ENDPOINT_OUT)
|
||||||
#define ELAN_EP_CMD_IN (0x3 | LIBUSB_ENDPOINT_IN)
|
#define ELAN_EP_CMD_IN (0x3 | FPI_USB_ENDPOINT_IN)
|
||||||
#define ELAN_EP_IMG_IN (0x2 | LIBUSB_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
|
/* usual command timeout and timeout for when we need to check if the finger is
|
||||||
* still on the device */
|
* still on the device */
|
||||||
#define ELAN_CMD_TIMEOUT 10000
|
#define ELAN_CMD_TIMEOUT 10000
|
||||||
#define ELAN_FINGER_TIMEOUT 200
|
#define ELAN_FINGER_TIMEOUT 200
|
||||||
|
|
||||||
struct elan_cmd {
|
struct elan_cmd
|
||||||
|
{
|
||||||
unsigned char cmd[ELAN_CMD_LEN];
|
unsigned char cmd[ELAN_CMD_LEN];
|
||||||
int response_len;
|
int response_len;
|
||||||
int response_in;
|
int response_in;
|
||||||
|
unsigned short devices;
|
||||||
|
gboolean never_cancel;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct elan_cmd get_sensor_dim_cmds[] = {
|
static const struct elan_cmd get_sensor_dim_cmd = {
|
||||||
{
|
|
||||||
.cmd = {0x00, 0x0c},
|
.cmd = {0x00, 0x0c},
|
||||||
.response_len = 0x4,
|
.response_len = 0x4,
|
||||||
.response_in = ELAN_EP_CMD_IN,
|
.response_in = ELAN_EP_CMD_IN,
|
||||||
},
|
.devices = ELAN_ALL_DEV,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const size_t get_sensor_dim_cmds_len =
|
static const struct elan_cmd get_fw_ver_cmd = {
|
||||||
G_N_ELEMENTS(get_sensor_dim_cmds);
|
|
||||||
|
|
||||||
static const struct elan_cmd init_start_cmds[] = {
|
|
||||||
{
|
|
||||||
.cmd = {0x40, 0x19},
|
.cmd = {0x40, 0x19},
|
||||||
.response_len = 0x2,
|
.response_len = 0x2,
|
||||||
.response_in = ELAN_EP_CMD_IN,
|
.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},
|
.cmd = {0x40, 0x2a},
|
||||||
.response_len = 0x2,
|
.response_len = 0x2,
|
||||||
.response_in = ELAN_EP_CMD_IN,
|
.response_in = ELAN_EP_CMD_IN,
|
||||||
},
|
.devices = ELAN_0907,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const size_t init_start_cmds_len = G_N_ELEMENTS(init_start_cmds);
|
static const struct elan_cmd get_image_cmd = {
|
||||||
|
|
||||||
static const struct elan_cmd read_cmds[] = {
|
|
||||||
/* raw frame sizes are calculated from image dimesions reported by the
|
|
||||||
* device */
|
|
||||||
{
|
|
||||||
.cmd = {0x00, 0x09},
|
.cmd = {0x00, 0x09},
|
||||||
|
/* raw frame sizes are calculated from image dimensions reported by the
|
||||||
|
* device */
|
||||||
.response_len = -1,
|
.response_len = -1,
|
||||||
.response_in = ELAN_EP_IMG_IN,
|
.response_in = ELAN_EP_IMG_IN,
|
||||||
},
|
.devices = ELAN_ALL_DEV,
|
||||||
};
|
};
|
||||||
|
|
||||||
const size_t read_cmds_len = G_N_ELEMENTS(read_cmds);
|
static const struct elan_cmd read_sensor_status_cmd = {
|
||||||
|
.cmd = {0x40, 0x13},
|
||||||
/* issued after data reads during init and calibration */
|
.response_len = 0x1,
|
||||||
static const struct elan_cmd init_end_cmds[] = {
|
|
||||||
{
|
|
||||||
.cmd = {0x40, 0x24},
|
|
||||||
.response_len = 0x2,
|
|
||||||
.response_in = ELAN_EP_CMD_IN,
|
.response_in = ELAN_EP_CMD_IN,
|
||||||
},
|
.devices = ELAN_ALL_DEV,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const size_t init_end_cmds_len = G_N_ELEMENTS(init_end_cmds);
|
static const struct elan_cmd get_calib_status_cmd = {
|
||||||
|
|
||||||
/* same command 2 times
|
|
||||||
* original driver may observe return value to determine how many times it
|
|
||||||
* should be repeated */
|
|
||||||
static const struct elan_cmd calibrate_start_cmds[] = {
|
|
||||||
{
|
|
||||||
.cmd = {0x40, 0x23},
|
.cmd = {0x40, 0x23},
|
||||||
.response_len = 0x1,
|
.response_len = 0x1,
|
||||||
.response_in = ELAN_EP_CMD_IN,
|
.response_in = ELAN_EP_CMD_IN,
|
||||||
},
|
.devices = ELAN_ALL_DEV,
|
||||||
{
|
|
||||||
.cmd = {0x40, 0x23},
|
|
||||||
.response_len = 0x1,
|
|
||||||
.response_in = ELAN_EP_CMD_IN,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const size_t calibrate_start_cmds_len =
|
static const struct elan_cmd get_calib_mean_cmd = {
|
||||||
G_N_ELEMENTS(calibrate_start_cmds);
|
|
||||||
|
|
||||||
/* issued after data reads during init and calibration */
|
|
||||||
static const struct elan_cmd calibrate_end_cmds[] = {
|
|
||||||
{
|
|
||||||
.cmd = {0x40, 0x24},
|
.cmd = {0x40, 0x24},
|
||||||
.response_len = 0x2,
|
.response_len = 0x2,
|
||||||
.response_in = ELAN_EP_CMD_IN,
|
.response_in = ELAN_EP_CMD_IN,
|
||||||
},
|
.devices = ELAN_ALL_DEV,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const size_t calibrate_end_cmds_len =
|
static const struct elan_cmd led_on_cmd = {
|
||||||
G_N_ELEMENTS(calibrate_end_cmds);
|
|
||||||
|
|
||||||
static const struct elan_cmd capture_start_cmds[] = {
|
|
||||||
/* led on */
|
|
||||||
{
|
|
||||||
.cmd = {0x40, 0x31},
|
.cmd = {0x40, 0x31},
|
||||||
.response_len = 0x0,
|
.response_len = ELAN_CMD_SKIP_READ,
|
||||||
.response_in = ELAN_EP_CMD_IN,
|
.response_in = ELAN_EP_CMD_IN,
|
||||||
},
|
.devices = ELAN_ALL_DEV,
|
||||||
};
|
};
|
||||||
|
|
||||||
static size_t capture_start_cmds_len = G_N_ELEMENTS(capture_start_cmds);
|
|
||||||
|
|
||||||
static const struct elan_cmd capture_wait_finger_cmds[] = {
|
|
||||||
/* wait for finger
|
/* wait for finger
|
||||||
* subsequent read will not complete until finger is placed on the reader */
|
* subsequent read will not complete until finger is placed on the reader */
|
||||||
{
|
static const struct elan_cmd pre_scan_cmd = {
|
||||||
.cmd = {0x40, 0x3f},
|
.cmd = {0x40, 0x3f},
|
||||||
.response_len = 0x1,
|
.response_len = 0x1,
|
||||||
.response_in = ELAN_EP_CMD_IN,
|
.response_in = ELAN_EP_CMD_IN,
|
||||||
},
|
.devices = ELAN_ALL_DEV,
|
||||||
};
|
};
|
||||||
|
|
||||||
static size_t capture_wait_finger_cmds_len =
|
/* led off, stop waiting for finger */
|
||||||
G_N_ELEMENTS(capture_wait_finger_cmds);
|
static const struct elan_cmd stop_cmd = {
|
||||||
|
|
||||||
static const struct elan_cmd deactivate_cmds[] = {
|
|
||||||
/* led off */
|
|
||||||
{
|
|
||||||
.cmd = {0x00, 0x0b},
|
.cmd = {0x00, 0x0b},
|
||||||
.response_len = 0x0,
|
.response_len = ELAN_CMD_SKIP_READ,
|
||||||
.response_in = ELAN_EP_CMD_IN,
|
.response_in = ELAN_EP_CMD_IN,
|
||||||
},
|
.devices = ELAN_ALL_DEV,
|
||||||
|
.never_cancel = TRUE,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const size_t deactivate_cmds_len = G_N_ELEMENTS(deactivate_cmds);
|
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 = 0x0c42, .driver_data = ELAN_0C42},
|
||||||
|
{.vid = 0, .pid = 0, .driver_data = 0},
|
||||||
|
};
|
||||||
|
|
||||||
static void elan_cmd_cb(struct libusb_transfer *transfer);
|
static void elan_cmd_done (FpiSsm *ssm);
|
||||||
static void elan_cmd_read(struct fpi_ssm *ssm);
|
static void elan_cmd_read (FpiSsm *ssm,
|
||||||
static void elan_run_next_cmd(struct fpi_ssm *ssm);
|
FpDevice *dev);
|
||||||
|
|
||||||
static void elan_capture(struct fp_img_dev *dev);
|
static void elan_calibrate (FpDevice *dev);
|
||||||
|
static void elan_capture (FpDevice *dev);
|
||||||
|
|
||||||
#endif
|
static void dev_change_state (FpImageDevice *dev,
|
||||||
|
FpiImageDeviceState state);
|
||||||
|
|||||||
@@ -1,318 +0,0 @@
|
|||||||
/*
|
|
||||||
* Secugen FDU2000 driver for libfprint
|
|
||||||
* Copyright (C) 2007 Gustavo Chain <g@0xff.cl>
|
|
||||||
*
|
|
||||||
* 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 "fdu2000"
|
|
||||||
|
|
||||||
#include "drivers_api.h"
|
|
||||||
|
|
||||||
#ifndef HAVE_MEMMEM
|
|
||||||
gpointer
|
|
||||||
memmem(const gpointer haystack, size_t haystack_len, const gpointer needle, size_t needle_len) {
|
|
||||||
const gchar *begin;
|
|
||||||
const char *const last_possible = (const char *) haystack + haystack_len - needle_len;
|
|
||||||
|
|
||||||
/* The first occurrence of the empty string is deemed to occur at
|
|
||||||
* the beginning of the string. */
|
|
||||||
if (needle_len == 0)
|
|
||||||
return (void *) haystack;
|
|
||||||
|
|
||||||
/* Sanity check, otherwise the loop might search through the whole
|
|
||||||
* memory. */
|
|
||||||
if (haystack_len < needle_len)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
for (begin = (const char *) haystack; begin <= last_possible; ++begin)
|
|
||||||
if (begin[0] == ((const char *) needle)[0] &&
|
|
||||||
!memcmp((const void *) &begin[1],
|
|
||||||
(const void *) ((const char *) needle + 1),
|
|
||||||
needle_len - 1))
|
|
||||||
return (void *) begin;
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
#endif /* HAVE_MEMMEM */
|
|
||||||
|
|
||||||
#define EP_IMAGE ( 0x02 | LIBUSB_ENDPOINT_IN )
|
|
||||||
#define EP_REPLY ( 0x01 | LIBUSB_ENDPOINT_IN )
|
|
||||||
#define EP_CMD ( 0x01 | LIBUSB_ENDPOINT_OUT )
|
|
||||||
#define BULK_TIMEOUT 200
|
|
||||||
|
|
||||||
/* fdu_req[] index */
|
|
||||||
typedef enum {
|
|
||||||
CAPTURE_READY,
|
|
||||||
CAPTURE_READ,
|
|
||||||
CAPTURE_END,
|
|
||||||
LED_OFF,
|
|
||||||
LED_ON
|
|
||||||
} req_index;
|
|
||||||
|
|
||||||
|
|
||||||
#define CMD_LEN 2
|
|
||||||
#define ACK_LEN 8
|
|
||||||
static const struct fdu2000_req {
|
|
||||||
const gchar cmd[CMD_LEN]; // Command to send
|
|
||||||
const gchar ack[ACK_LEN]; // Expected ACK
|
|
||||||
const guint ack_len; // ACK has variable length
|
|
||||||
} fdu_req[] = {
|
|
||||||
/* Capture */
|
|
||||||
{
|
|
||||||
.cmd = { 0x00, 0x04 },
|
|
||||||
.ack = { 0x00, 0x04, 0x01, 0x01 },
|
|
||||||
.ack_len = 4
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
.cmd = { 0x00, 0x01 },
|
|
||||||
.ack = { 0x00, 0x01, 0x01, 0x01 },
|
|
||||||
.ack_len = 4
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
.cmd = { 0x00, 0x05 },
|
|
||||||
.ack = { 0x00, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
|
|
||||||
.ack_len = 8
|
|
||||||
},
|
|
||||||
|
|
||||||
/* Led */
|
|
||||||
{
|
|
||||||
.cmd = { 0x05, 0x00 },
|
|
||||||
.ack = {},
|
|
||||||
.ack_len = 0
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
.cmd = { 0x05, 0x01 },
|
|
||||||
.ack = {},
|
|
||||||
.ack_len = 0
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Write a command and verify reponse
|
|
||||||
*/
|
|
||||||
static gint
|
|
||||||
bulk_write_safe(libusb_dev_handle *dev, req_index rIndex) {
|
|
||||||
|
|
||||||
gchar reponse[ACK_LEN];
|
|
||||||
gint r;
|
|
||||||
gchar *cmd = (gchar *)fdu_req[rIndex].cmd;
|
|
||||||
gchar *ack = (gchar *)fdu_req[rIndex].ack;
|
|
||||||
gint ack_len = fdu_req[rIndex].ack_len;
|
|
||||||
struct libusb_bulk_transfer wrmsg = {
|
|
||||||
.endpoint = EP_CMD,
|
|
||||||
.data = cmd,
|
|
||||||
.length = sizeof(cmd),
|
|
||||||
};
|
|
||||||
struct libusb_bulk_transfer readmsg = {
|
|
||||||
.endpoint = EP_REPLY,
|
|
||||||
.data = reponse,
|
|
||||||
.length = sizeof(reponse),
|
|
||||||
};
|
|
||||||
int trf;
|
|
||||||
|
|
||||||
r = libusb_bulk_transfer(dev, &wrmsg, &trf, BULK_TIMEOUT);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
if (ack_len == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* Check reply from FP */
|
|
||||||
r = libusb_bulk_transfer(dev, &readmsg, &trf, BULK_TIMEOUT);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
if (!strncmp(ack, reponse, ack_len))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
fp_err("Expected different ACK from dev");
|
|
||||||
return 1; /* Error */
|
|
||||||
}
|
|
||||||
|
|
||||||
static gint
|
|
||||||
capture(struct fp_img_dev *dev, gboolean unconditional,
|
|
||||||
struct fp_img **ret)
|
|
||||||
{
|
|
||||||
#define RAW_IMAGE_WIDTH 398
|
|
||||||
#define RAW_IMAGE_HEIGTH 301
|
|
||||||
#define RAW_IMAGE_SIZE (RAW_IMAGE_WIDTH * RAW_IMAGE_HEIGTH)
|
|
||||||
|
|
||||||
struct fp_img *img = NULL;
|
|
||||||
int bytes, r;
|
|
||||||
const gchar SOF[] = { 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x0c, 0x07 }; // Start of frame
|
|
||||||
const gchar SOL[] = { 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x0b, 0x06 }; // Start of line + { L L } (L: Line num) (8 nibbles)
|
|
||||||
gchar *buffer = g_malloc0(RAW_IMAGE_SIZE * 6);
|
|
||||||
gchar *image;
|
|
||||||
gchar *p;
|
|
||||||
guint offset;
|
|
||||||
struct libusb_bulk_transfer msg = {
|
|
||||||
.endpoint = EP_IMAGE,
|
|
||||||
.data = buffer,
|
|
||||||
.length = RAW_IMAGE_SIZE * 6,
|
|
||||||
};
|
|
||||||
|
|
||||||
image = g_malloc0(RAW_IMAGE_SIZE);
|
|
||||||
|
|
||||||
if ((r = bulk_write_safe(fpi_imgdev_get_usb_dev(dev), LED_ON))) {
|
|
||||||
fp_err("Command: LED_ON");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((r = bulk_write_safe(fpi_imgdev_get_usb_dev(dev), CAPTURE_READY))) {
|
|
||||||
fp_err("Command: CAPTURE_READY");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
read:
|
|
||||||
if ((r = bulk_write_safe(fpi_imgdev_get_usb_dev(dev), CAPTURE_READ))) {
|
|
||||||
fp_err("Command: CAPTURE_READ");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now we are ready to read from dev */
|
|
||||||
|
|
||||||
r = libusb_bulk_transfer(fpi_imgdev_get_usb_dev(dev), &msg, &bytes, BULK_TIMEOUT * 10);
|
|
||||||
if (r < 0 || bytes < 1)
|
|
||||||
goto read;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Find SOF (start of line)
|
|
||||||
*/
|
|
||||||
p = memmem(buffer, RAW_IMAGE_SIZE * 6,
|
|
||||||
(const gpointer)SOF, sizeof SOF);
|
|
||||||
fp_dbg("Read %d byte/s from dev", bytes);
|
|
||||||
if (!p)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
p += sizeof SOF;
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
bytes = 0;
|
|
||||||
while(p) {
|
|
||||||
if ( i >= RAW_IMAGE_HEIGTH )
|
|
||||||
break;
|
|
||||||
|
|
||||||
offset = p - buffer;
|
|
||||||
p = memmem(p, (RAW_IMAGE_SIZE * 6) - (offset),
|
|
||||||
(const gpointer)SOL, sizeof SOL);
|
|
||||||
if (p) {
|
|
||||||
p += sizeof SOL + 4;
|
|
||||||
int j;
|
|
||||||
for (j = 0; j < RAW_IMAGE_WIDTH; j++) {
|
|
||||||
/**
|
|
||||||
* Convert from 4 to 8 bits
|
|
||||||
* The SECUGEN-FDU2000 has 4 lines of data, so we need to join 2 bytes into 1
|
|
||||||
*/
|
|
||||||
*(image + bytes + j) = *(p + (j * 2) + 0) << 4 & 0xf0;
|
|
||||||
*(image + bytes + j) |= *(p + (j * 2) + 1) & 0x0f;
|
|
||||||
}
|
|
||||||
p += RAW_IMAGE_WIDTH * 2;
|
|
||||||
bytes += RAW_IMAGE_WIDTH;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((r = bulk_write_safe(fpi_imgdev_get_usb_dev(dev), CAPTURE_END))) {
|
|
||||||
fp_err("Command: CAPTURE_END");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((r = bulk_write_safe(fpi_imgdev_get_usb_dev(dev), LED_OFF))) {
|
|
||||||
fp_err("Command: LED_OFF");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
img = fpi_img_new_for_imgdev(dev);
|
|
||||||
memcpy(img->data, image, RAW_IMAGE_SIZE);
|
|
||||||
img->flags = FP_IMG_COLORS_INVERTED | FP_IMG_V_FLIPPED | FP_IMG_H_FLIPPED;
|
|
||||||
*ret = img;
|
|
||||||
|
|
||||||
out:
|
|
||||||
g_free(buffer);
|
|
||||||
g_free(image);
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
gint dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
|
||||||
{
|
|
||||||
gint r;
|
|
||||||
//if ( (r = usb_set_configuration(fpi_imgdev_get_usb_dev(dev), 1)) < 0 )
|
|
||||||
// goto out;
|
|
||||||
|
|
||||||
if ( (r = libusb_claim_interface(fpi_imgdev_get_usb_dev(dev), 0)) < 0 ) {
|
|
||||||
fp_err("could not claim interface 0: %s", libusb_error_name(r));
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
//if ( (r = usb_set_altinterface(fpi_imgdev_get_usb_dev(dev), 1)) < 0 )
|
|
||||||
// goto out;
|
|
||||||
|
|
||||||
//if ( (r = usb_clear_halt(fpi_imgdev_get_usb_dev(dev), EP_CMD)) < 0 )
|
|
||||||
// goto out;
|
|
||||||
|
|
||||||
/* Make sure sensor mode is not capture_{ready|read} */
|
|
||||||
if ((r = bulk_write_safe(fpi_imgdev_get_usb_dev(dev), CAPTURE_END))) {
|
|
||||||
fp_err("Command: CAPTURE_END");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((r = bulk_write_safe(fpi_imgdev_get_usb_dev(dev), LED_OFF))) {
|
|
||||||
fp_err("Command: LED_OFF");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
out:
|
|
||||||
fp_err("could not init dev");
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
void dev_exit(struct fp_img_dev *dev)
|
|
||||||
{
|
|
||||||
if (bulk_write_safe(fpi_imgdev_get_usb_dev(dev), CAPTURE_END))
|
|
||||||
fp_err("Command: CAPTURE_END");
|
|
||||||
|
|
||||||
libusb_release_interface(fpi_imgdev_get_usb_dev(dev), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct usb_id id_table[] = {
|
|
||||||
{ .vendor = 0x1162, .product = 0x0300 },
|
|
||||||
{ 0, 0, 0, },
|
|
||||||
};
|
|
||||||
|
|
||||||
struct fp_img_driver fdu2000_driver = {
|
|
||||||
.driver = {
|
|
||||||
.id = FDU2000_ID,
|
|
||||||
.name = FP_COMPONENT,
|
|
||||||
.full_name = "Secugen FDU 2000",
|
|
||||||
.id_table = id_table,
|
|
||||||
.scan_type = FP_SCAN_TYPE_PRESS,
|
|
||||||
},
|
|
||||||
.img_height = RAW_IMAGE_HEIGTH,
|
|
||||||
.img_width = RAW_IMAGE_WIDTH,
|
|
||||||
.bz3_threshold = 23,
|
|
||||||
|
|
||||||
.init = dev_init,
|
|
||||||
.exit = dev_exit,
|
|
||||||
.capture = capture,
|
|
||||||
};
|
|
||||||
229
libfprint/drivers/synaptics/bmkt.h
Normal file
@@ -0,0 +1,229 @@
|
|||||||
|
/*
|
||||||
|
* Synaptics MiS Fingerprint Sensor Interface
|
||||||
|
* Copyright (C) 2019 Synaptics Inc
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
/**< User ID maximum length allowed */
|
||||||
|
#define BMKT_MAX_USER_ID_LEN 100
|
||||||
|
/**< Software Part Number length */
|
||||||
|
#define BMKT_PART_NUM_LEN 10
|
||||||
|
/**< Software supplier identification length */
|
||||||
|
#define BMKT_SUPPLIER_ID_LEN 2
|
||||||
|
|
||||||
|
/**< Maximum namber of templates for storing in internal flash of the fingerprint sensor */
|
||||||
|
#define BMKT_MAX_NUM_TEMPLATES_INTERNAL_FLASH 15
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "bmkt_response.h"
|
||||||
|
|
||||||
|
/*!
|
||||||
|
*******************************************************************************
|
||||||
|
** Type definition for result
|
||||||
|
*/
|
||||||
|
/** No error; Operation successfully completed. */
|
||||||
|
#define BMKT_SUCCESS 0
|
||||||
|
/** Fingerprint system not initialized */
|
||||||
|
#define BMKT_FP_SYSTEM_NOT_INITIALIZED 101
|
||||||
|
/** Fingerprint system busy performing another operation */
|
||||||
|
#define BMKT_FP_SYSTEM_BUSY 102
|
||||||
|
/** Operation not allowed */
|
||||||
|
#define BMKT_OPERATION_DENIED 103
|
||||||
|
/** System ran out of memory while performing operation */
|
||||||
|
#define BMKT_OUT_OF_MEMORY 104
|
||||||
|
/** Corrupt message, CRC check fail or truncated message */
|
||||||
|
#define BMKT_CORRUPT_MESSAGE 110
|
||||||
|
/** One of the command parameters is outside the range of valid values */
|
||||||
|
#define BMKT_INVALID_PARAM 111
|
||||||
|
/** Unrecognized message or message with invalid message ID */
|
||||||
|
#define BMKT_UNRECOGNIZED_MESSAGE 112
|
||||||
|
/** Operation time out */
|
||||||
|
#define BMKT_OP_TIME_OUT 113
|
||||||
|
/** General error – cause of error cannot be determined */
|
||||||
|
#define BMKT_GENERAL_ERROR 114
|
||||||
|
|
||||||
|
#define BMKT_SET_SECURITY_LEVEL_FAIL 120
|
||||||
|
#define BMKT_GET_SECURITY_LEVEL_FAIL 121
|
||||||
|
|
||||||
|
/** Fingerprint sensor reset while operation was being performed */
|
||||||
|
#define BMKT_SENSOR_RESET 201
|
||||||
|
/** Fingerprint sensor malfunctioned */
|
||||||
|
#define BMKT_SENSOR_MALFUNCTION 202
|
||||||
|
/** Fingerprint sensor cannot be accessed despite repeated attempts */
|
||||||
|
#define BMKT_SENSOR_TAMPERED 203
|
||||||
|
/**
|
||||||
|
* BMKT_SENSOR_NOT_INIT:
|
||||||
|
* Fingerprint sensor module not initialized yet – not ready for use
|
||||||
|
* (different from error code 101 which indicates that the entire system
|
||||||
|
* has not been initialized)
|
||||||
|
*/
|
||||||
|
#define BMKT_SENSOR_NOT_INIT 204
|
||||||
|
/** Number of re-pairing operations exceeded limit or re-pairing has been disabled */
|
||||||
|
#define BMKT_OWNERSHIP_RESET_MAX_EXCEEDED 205
|
||||||
|
/**
|
||||||
|
* BMKT_SENSOR_STIMULUS_ERROR:
|
||||||
|
* There is a finger or debris on the sensor that needs to be removed
|
||||||
|
* before issuing this command
|
||||||
|
*/
|
||||||
|
#define BMKT_SENSOR_STIMULUS_ERROR 213
|
||||||
|
/**
|
||||||
|
* BMKT_CORRUPT_TEMPLATE_DATA:
|
||||||
|
* One of the fingerprint templates stored on flash is corrupt.
|
||||||
|
* This error code is returned in case of failure in finding a fingerprint match
|
||||||
|
* during identify or verify operations while also detecting that one or more
|
||||||
|
* fingerprint templates stored on the flash has become corrupted
|
||||||
|
*/
|
||||||
|
#define BMKT_CORRUPT_TEMPLATE_DATA 300
|
||||||
|
/** Failed to extract features from fingerprint image acquired by sensor */
|
||||||
|
#define BMKT_FEATURE_EXTRACT_FAIL 301
|
||||||
|
/** Failed to generate fingerprint template */
|
||||||
|
#define BMKT_ENROLL_FAIL 302
|
||||||
|
/** Specified finger already enrolled for this user */
|
||||||
|
#define BMKT_ENROLLMENT_EXISTS 303
|
||||||
|
/** Invalid fingerprint image */
|
||||||
|
#define BMKT_INVALID_FP_IMAGE 304
|
||||||
|
/** No matching user fingerprint template found in database */
|
||||||
|
#define BMKT_FP_NO_MATCH 404
|
||||||
|
/** Fingerprint database is full */
|
||||||
|
#define BMKT_FP_DATABASE_FULL 501
|
||||||
|
/** Fingerprint database is empty */
|
||||||
|
#define BMKT_FP_DATABASE_EMPTY 502
|
||||||
|
/** Cannot access fingerprint database */
|
||||||
|
#define BMKT_FP_DATABASE_ACCESS_FAIL 503
|
||||||
|
/** Fingerprint template record does not exist */
|
||||||
|
#define BMKT_FP_DATABASE_NO_RECORD_EXISTS 504
|
||||||
|
/** Failed to read/write system parameters stored on flash */
|
||||||
|
#define BMKT_FP_PARAM_ACCESS_FAIL 505
|
||||||
|
/** Fingerprint is a spoof */
|
||||||
|
#define BMKT_FP_SPOOF_ALERT 801
|
||||||
|
/** Anti-spoof module failure */
|
||||||
|
#define BMKT_ANTI_SPOOF_MODULE_FAIL 802
|
||||||
|
|
||||||
|
#define BMKT_CORRUPT_UPDATE_IMAGE 901
|
||||||
|
#define BMKT_SYSTEM_UPDATE_FAIL 902
|
||||||
|
|
||||||
|
#define BMKT_EVENT_NOT_SET 1000
|
||||||
|
#define BMKT_SENSOR_NOT_READY 1001
|
||||||
|
#define BMKT_TIMEOUT 1002
|
||||||
|
#define BMKT_SENSOR_RESPONSE_PENDING 1003
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bmkt_mode:
|
||||||
|
* Fingerprint system operational mode values level 1
|
||||||
|
*/
|
||||||
|
typedef enum bmkt_mode {
|
||||||
|
BMKT_STATE_UNINIT = 0xFF,
|
||||||
|
BMKT_STATE_IDLE = 0x00,
|
||||||
|
BMKT_STATE_ENROLL = 0x10,
|
||||||
|
BMKT_STATE_IDENTIFY = 0x20,
|
||||||
|
BMKT_STATE_VERIFY = 0x30,
|
||||||
|
BMKT_STATE_DB_OPS = 0x40,
|
||||||
|
BMKT_STATE_SYS_TEST = 0x50,
|
||||||
|
BMKT_STATE_SYS_OPS = 0x60,
|
||||||
|
} bmkt_mode_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bmkt_mode_level2:
|
||||||
|
* Fingerprint system operational mode values level 2
|
||||||
|
*/
|
||||||
|
typedef enum bmkt_mode_level2 {
|
||||||
|
BMKT_STATE_L2_IDLE = 0x00,
|
||||||
|
BMKT_STATE_L2_STARTING = 0x11,
|
||||||
|
BMKT_STATE_L2_WAITING_FOR_FINGER = 0x12,
|
||||||
|
BMKT_STATE_L2_CAPTURE_IMAGE = 0x13,
|
||||||
|
BMKT_STATE_L2_CAPTURE_COMPLETE = 0x14,
|
||||||
|
BMKT_STATE_L2_EXTRACT_FEATURE = 0x15,
|
||||||
|
BMKT_STATE_L2_CREATE_TEMPLATE = 0x16,
|
||||||
|
BMKT_STATE_L2_READING_FROM_FLASH = 0x17,
|
||||||
|
BMKT_STATE_L2_WRITING_TO_FLASH = 0x18,
|
||||||
|
BMKT_STATE_L2_FINISHING = 0x19,
|
||||||
|
BMKT_STATE_L2_CANCELING_OP = 0x20,
|
||||||
|
BMKT_STATE_L2_MATCHING = 0x21,
|
||||||
|
BMKT_STATE_L2_TRANSMITTING_RESPONSE = 0x22,
|
||||||
|
BMKT_STATE_L2_READY_POWER_DOWN = 0xF0,
|
||||||
|
} bmkt_mode_level2_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bmkt_transport_type:
|
||||||
|
* Fingerprint system transport types
|
||||||
|
*/
|
||||||
|
typedef enum bmkt_transport_type {
|
||||||
|
BMKT_TRANSPORT_TYPE_USB = 0,
|
||||||
|
} bmkt_transport_type_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bmkt_usb_config:
|
||||||
|
* Structure represcontainingenting USB configuration details
|
||||||
|
*/
|
||||||
|
typedef struct bmkt_usb_config
|
||||||
|
{
|
||||||
|
int product_id; /**< USB device product ID */
|
||||||
|
} bmkt_usb_config_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bmkt_transport_config_t:
|
||||||
|
* Union containing transport configuration details
|
||||||
|
*/
|
||||||
|
typedef union
|
||||||
|
{
|
||||||
|
bmkt_usb_config_t usb_config;
|
||||||
|
} bmkt_transport_config_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bmkt_sensor_desc_t:
|
||||||
|
* Structure containing fingerprint system description
|
||||||
|
*/
|
||||||
|
typedef struct bmkt_sensor_desc
|
||||||
|
{
|
||||||
|
int product_id;
|
||||||
|
int flags;
|
||||||
|
} bmkt_sensor_desc_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bmkt_finger_state_t:
|
||||||
|
* Finger state representation values.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
BMKT_FINGER_STATE_UNKNOWN = 0,
|
||||||
|
BMKT_FINGER_STATE_ON_SENSOR,
|
||||||
|
BMKT_FINGER_STATE_NOT_ON_SENSOR,
|
||||||
|
} bmkt_finger_state_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bmkt_finger_event_t:
|
||||||
|
* Structure containing finger state
|
||||||
|
*/
|
||||||
|
typedef struct bmkt_finger_event
|
||||||
|
{
|
||||||
|
bmkt_finger_state_t finger_state;
|
||||||
|
} bmkt_finger_event_t;
|
||||||
|
|
||||||
|
typedef struct bmkt_user_id
|
||||||
|
{
|
||||||
|
uint8_t user_id_len;
|
||||||
|
uint8_t user_id[BMKT_MAX_USER_ID_LEN];
|
||||||
|
} bmkt_user_id_t;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
400
libfprint/drivers/synaptics/bmkt_message.c
Normal file
@@ -0,0 +1,400 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 Synaptics Inc
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include "bmkt_response.h"
|
||||||
|
#include "bmkt_message.h"
|
||||||
|
|
||||||
|
static uint8_t
|
||||||
|
extract8 (const uint8_t *buf, int *offset)
|
||||||
|
{
|
||||||
|
uint8_t ret = 0;
|
||||||
|
int off = 0;
|
||||||
|
|
||||||
|
if (offset)
|
||||||
|
off = *offset;
|
||||||
|
|
||||||
|
ret = *(buf + off);
|
||||||
|
|
||||||
|
if (offset)
|
||||||
|
*offset += 1;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
parse_error_response (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
|
||||||
|
{
|
||||||
|
if (msg_resp->payload_len != 2)
|
||||||
|
return BMKT_UNRECOGNIZED_MESSAGE;
|
||||||
|
|
||||||
|
resp->result = (msg_resp->payload[0] << 8) | msg_resp->payload[1];
|
||||||
|
|
||||||
|
return BMKT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
parse_init_ok (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
|
||||||
|
{
|
||||||
|
bmkt_init_resp_t *init_resp = &resp->response.init_resp;
|
||||||
|
|
||||||
|
if (msg_resp->payload_len != 1)
|
||||||
|
return BMKT_UNRECOGNIZED_MESSAGE;
|
||||||
|
|
||||||
|
init_resp->finger_presence = extract8 (msg_resp->payload, NULL);
|
||||||
|
|
||||||
|
return BMKT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
parse_fps_mode_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
|
||||||
|
{
|
||||||
|
int offset = 0;
|
||||||
|
bmkt_fps_mode_resp_t *fps_mode_resp = &resp->response.fps_mode_resp;
|
||||||
|
|
||||||
|
if (msg_resp->payload_len != sizeof (bmkt_fps_mode_resp_t))
|
||||||
|
return BMKT_UNRECOGNIZED_MESSAGE;
|
||||||
|
|
||||||
|
fps_mode_resp->mode = extract8 (msg_resp->payload, &offset);
|
||||||
|
fps_mode_resp->level2_mode = extract8 (msg_resp->payload, &offset);
|
||||||
|
fps_mode_resp->cmd_id = extract8 (msg_resp->payload, &offset);
|
||||||
|
fps_mode_resp->finger_presence = extract8 (msg_resp->payload, &offset);
|
||||||
|
|
||||||
|
return BMKT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
parse_enroll_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
|
||||||
|
{
|
||||||
|
bmkt_enroll_resp_t *enroll_resp = &resp->response.enroll_resp;
|
||||||
|
|
||||||
|
if (msg_resp->payload_len != 1)
|
||||||
|
return BMKT_UNRECOGNIZED_MESSAGE;
|
||||||
|
|
||||||
|
enroll_resp->progress = extract8 (msg_resp->payload, NULL);
|
||||||
|
|
||||||
|
return BMKT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
parse_enroll_ok (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
|
||||||
|
{
|
||||||
|
bmkt_enroll_resp_t *enroll_resp = &resp->response.enroll_resp;
|
||||||
|
|
||||||
|
if (msg_resp->payload_len < 1 || msg_resp->payload_len > (BMKT_MAX_USER_ID_LEN + 1))
|
||||||
|
return BMKT_UNRECOGNIZED_MESSAGE;
|
||||||
|
|
||||||
|
enroll_resp->finger_id = msg_resp->payload[0];
|
||||||
|
memcpy (enroll_resp->user_id, &msg_resp->payload[1], msg_resp->payload_len - 1);
|
||||||
|
|
||||||
|
return BMKT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
parse_auth_ok (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
|
||||||
|
{
|
||||||
|
bmkt_identify_resp_t *id_resp = &resp->response.id_resp;
|
||||||
|
|
||||||
|
if (msg_resp->payload_len < 3 || msg_resp->payload_len > (BMKT_MAX_USER_ID_LEN + 3))
|
||||||
|
return BMKT_UNRECOGNIZED_MESSAGE;
|
||||||
|
|
||||||
|
id_resp->match_result = (double) msg_resp->payload[0] + 0.01 * (double) msg_resp->payload[1];
|
||||||
|
id_resp->finger_id = msg_resp->payload[2];
|
||||||
|
memcpy (id_resp->user_id, &msg_resp->payload[3], msg_resp->payload_len - 3);
|
||||||
|
|
||||||
|
return BMKT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
parse_security_level_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
|
||||||
|
{
|
||||||
|
bmkt_set_sec_level_resp_t *sec_level_resp = &resp->response.sec_level_resp;
|
||||||
|
|
||||||
|
if (msg_resp->payload_len != 1)
|
||||||
|
return BMKT_UNRECOGNIZED_MESSAGE;
|
||||||
|
|
||||||
|
sec_level_resp->sec_level = extract8 (msg_resp->payload, NULL);
|
||||||
|
|
||||||
|
return BMKT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
parse_del_all_users_progress_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
|
||||||
|
{
|
||||||
|
bmkt_del_all_users_resp_t *del_all_users_resp = &resp->response.del_all_users_resp;
|
||||||
|
|
||||||
|
if (msg_resp->payload_len != 1)
|
||||||
|
return BMKT_UNRECOGNIZED_MESSAGE;
|
||||||
|
|
||||||
|
del_all_users_resp->progress = extract8 (msg_resp->payload, NULL);
|
||||||
|
|
||||||
|
return BMKT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
parse_db_cap_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
|
||||||
|
{
|
||||||
|
bmkt_get_db_capacity_resp_t *db_cap_resp = &resp->response.db_cap_resp;
|
||||||
|
int offset = 0;
|
||||||
|
|
||||||
|
if (msg_resp->payload_len < 2 || msg_resp->payload_len > 4)
|
||||||
|
return BMKT_UNRECOGNIZED_MESSAGE;
|
||||||
|
|
||||||
|
db_cap_resp->total = extract8 (msg_resp->payload, &offset);
|
||||||
|
db_cap_resp->empty = extract8 (msg_resp->payload, &offset);
|
||||||
|
|
||||||
|
if (msg_resp->payload_len == 4)
|
||||||
|
{
|
||||||
|
db_cap_resp->bad_slots = extract8 (msg_resp->payload, &offset);
|
||||||
|
db_cap_resp->corrupt_templates = extract8 (msg_resp->payload, &offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
return BMKT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
parse_get_enrolled_fingers_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
|
||||||
|
{
|
||||||
|
int offset = 0;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
if (msg_resp->payload_len < 2)
|
||||||
|
return BMKT_UNRECOGNIZED_MESSAGE;
|
||||||
|
/* 2 bytes per finger so calculate the total number of fingers to process*/
|
||||||
|
int num_fingers = (msg_resp->payload_len) / 2;
|
||||||
|
|
||||||
|
bmkt_enrolled_fingers_resp_t *get_enrolled_fingers_resp = &resp->response.enrolled_fingers_resp;
|
||||||
|
|
||||||
|
for (i = 0; i < num_fingers; i++)
|
||||||
|
{
|
||||||
|
get_enrolled_fingers_resp->fingers[i].finger_id = extract8 (msg_resp->payload, &offset);
|
||||||
|
get_enrolled_fingers_resp->fingers[i].template_status = extract8 (msg_resp->payload, &offset);
|
||||||
|
|
||||||
|
}
|
||||||
|
return BMKT_SUCCESS;
|
||||||
|
}
|
||||||
|
static int
|
||||||
|
parse_get_enrolled_users_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
|
||||||
|
{
|
||||||
|
int offset = 0;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
/* the payload is 2 bytes + template data */
|
||||||
|
if (msg_resp->payload_len < 2)
|
||||||
|
return BMKT_UNRECOGNIZED_MESSAGE;
|
||||||
|
|
||||||
|
bmkt_enroll_templates_resp_t *get_enroll_templates_resp = &resp->response.enroll_templates_resp;
|
||||||
|
|
||||||
|
get_enroll_templates_resp->total_query_messages = extract8 (msg_resp->payload, &offset);
|
||||||
|
get_enroll_templates_resp->query_sequence = extract8 (msg_resp->payload, &offset);
|
||||||
|
|
||||||
|
int n = 0;
|
||||||
|
for (n = 0; n < BMKT_MAX_NUM_TEMPLATES_INTERNAL_FLASH; n++)
|
||||||
|
{
|
||||||
|
if (offset >= msg_resp->payload_len)
|
||||||
|
break;
|
||||||
|
get_enroll_templates_resp->templates[n].user_id_len = extract8 (msg_resp->payload, &offset) - 2;
|
||||||
|
if(get_enroll_templates_resp->templates[n].user_id_len > BMKT_MAX_USER_ID_LEN)
|
||||||
|
return BMKT_UNRECOGNIZED_MESSAGE;
|
||||||
|
get_enroll_templates_resp->templates[n].template_status = extract8 (msg_resp->payload, &offset);
|
||||||
|
get_enroll_templates_resp->templates[n].finger_id = extract8 (msg_resp->payload, &offset);
|
||||||
|
for (i = 0; i < get_enroll_templates_resp->templates[n].user_id_len; i++)
|
||||||
|
get_enroll_templates_resp->templates[n].user_id[i] = extract8 (msg_resp->payload, &offset);
|
||||||
|
get_enroll_templates_resp->templates[n].user_id[i] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return BMKT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
parse_get_version_report (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
|
||||||
|
{
|
||||||
|
bmkt_get_version_resp_t *get_version_resp = &resp->response.get_version_resp;
|
||||||
|
int offset = 0;
|
||||||
|
|
||||||
|
if (msg_resp->payload_len != 15)
|
||||||
|
return BMKT_UNRECOGNIZED_MESSAGE;
|
||||||
|
|
||||||
|
memcpy (get_version_resp->part, msg_resp->payload, BMKT_PART_NUM_LEN);
|
||||||
|
offset += BMKT_PART_NUM_LEN;
|
||||||
|
get_version_resp->year = extract8 (msg_resp->payload, &offset);
|
||||||
|
get_version_resp->week = extract8 (msg_resp->payload, &offset);
|
||||||
|
get_version_resp->patch = extract8 (msg_resp->payload, &offset);
|
||||||
|
memcpy (get_version_resp->supplier_id, msg_resp->payload + offset, BMKT_SUPPLIER_ID_LEN);
|
||||||
|
|
||||||
|
return BMKT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
bmkt_compose_message (uint8_t *cmd, int *cmd_len, uint8_t msg_id, uint8_t seq_num,
|
||||||
|
uint8_t payload_size, const uint8_t *payload)
|
||||||
|
{
|
||||||
|
int message_len = BMKT_MESSAGE_HEADER_LEN + payload_size;
|
||||||
|
|
||||||
|
if (*cmd_len < message_len)
|
||||||
|
return BMKT_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
cmd[BMKT_MESSAGE_HEADER_ID_FIELD] = BMKT_MESSAGE_HEADER_ID;
|
||||||
|
cmd[BMKT_MESSAGE_SEQ_NUM_FIELD] = seq_num;
|
||||||
|
cmd[BMKT_MESSAGE_ID_FIELD] = msg_id;
|
||||||
|
cmd[BMKT_MESSAGE_PAYLOAD_LEN_FIELD] = payload_size;
|
||||||
|
memcpy (&cmd[BMKT_MESSAGE_PAYLOAD_FIELD], payload, payload_size);
|
||||||
|
|
||||||
|
*cmd_len = message_len;
|
||||||
|
|
||||||
|
return BMKT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
bmkt_parse_message_header (uint8_t *resp_buf, int resp_len, bmkt_msg_resp_t *msg_resp)
|
||||||
|
{
|
||||||
|
if (resp_buf[BMKT_MESSAGE_HEADER_ID_FIELD] != BMKT_MESSAGE_HEADER_ID)
|
||||||
|
return BMKT_CORRUPT_MESSAGE;
|
||||||
|
|
||||||
|
msg_resp->seq_num = resp_buf[BMKT_MESSAGE_SEQ_NUM_FIELD];
|
||||||
|
msg_resp->msg_id = resp_buf[BMKT_MESSAGE_ID_FIELD];
|
||||||
|
msg_resp->payload_len = resp_buf[BMKT_MESSAGE_PAYLOAD_LEN_FIELD];
|
||||||
|
if (msg_resp->payload_len > 0)
|
||||||
|
msg_resp->payload = &resp_buf[BMKT_MESSAGE_PAYLOAD_FIELD];
|
||||||
|
else
|
||||||
|
msg_resp->payload = NULL;
|
||||||
|
|
||||||
|
return BMKT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
bmkt_parse_message_payload (bmkt_msg_resp_t *msg_resp, bmkt_response_t *resp)
|
||||||
|
{
|
||||||
|
int ret = BMKT_SUCCESS;
|
||||||
|
|
||||||
|
memset (resp, 0, sizeof (bmkt_response_t));
|
||||||
|
|
||||||
|
resp->response_id = msg_resp->msg_id;
|
||||||
|
|
||||||
|
switch(msg_resp->msg_id)
|
||||||
|
{
|
||||||
|
case BMKT_RSP_CONTINUOUS_IMAGE_CAPTURE_FAIL:
|
||||||
|
case BMKT_RSP_SENSOR_MODULE_TEST_FAIL:
|
||||||
|
case BMKT_RSP_FPS_INIT_FAIL:
|
||||||
|
case BMKT_RSP_FPS_MODE_FAIL:
|
||||||
|
case BMKT_RSP_SET_SECURITY_LEVEL_FAIL:
|
||||||
|
case BMKT_RSP_GET_SECURITY_LEVEL_FAIL:
|
||||||
|
case BMKT_RSP_CANCEL_OP_FAIL:
|
||||||
|
case BMKT_RSP_ENROLL_FAIL:
|
||||||
|
case BMKT_RSP_ID_FAIL:
|
||||||
|
case BMKT_RSP_VERIFY_FAIL:
|
||||||
|
case BMKT_RSP_QUERY_FAIL:
|
||||||
|
case BMKT_RSP_DEL_USER_FP_FAIL:
|
||||||
|
case BMKT_RSP_DEL_FULL_DB_FAIL:
|
||||||
|
case BMKT_RSP_REPEAT_LAST_BMKT_RSP_FAIL:
|
||||||
|
case BMKT_RSP_POWER_DOWN_FAIL:
|
||||||
|
case BMKT_RSP_GET_VERSION_FAIL:
|
||||||
|
case BMKT_RSP_DISABLE_PAIRING_FAIL:
|
||||||
|
case BMKT_RSP_QUERY_PAIRING_FAIL:
|
||||||
|
case BMKT_RSP_SENSOR_STATUS_FAIL:
|
||||||
|
case BMKT_RSP_RETRIEVE_FINAL_RESULT_FAIL:
|
||||||
|
ret = parse_error_response (msg_resp, resp);
|
||||||
|
resp->complete = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BMKT_RSP_FPS_INIT_OK:
|
||||||
|
ret = parse_init_ok (msg_resp, resp);
|
||||||
|
resp->complete = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BMKT_RSP_CANCEL_OP_OK:
|
||||||
|
case BMKT_RSP_DEL_FULL_DB_OK:
|
||||||
|
case BMKT_RSP_DEL_USER_FP_OK:
|
||||||
|
/* responses with a payload of 0
|
||||||
|
so the response indicates success */
|
||||||
|
resp->result = BMKT_SUCCESS;
|
||||||
|
resp->complete = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BMKT_RSP_FPS_MODE_REPORT:
|
||||||
|
// parse_fps_mode
|
||||||
|
ret = parse_fps_mode_report (msg_resp, resp);
|
||||||
|
resp->complete = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BMKT_RSP_GET_SECURITY_LEVEL_REPORT:
|
||||||
|
case BMKT_RSP_SET_SECURITY_LEVEL_REPORT:
|
||||||
|
/* parse security level result */
|
||||||
|
ret = parse_security_level_report (msg_resp, resp);
|
||||||
|
resp->complete = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BMKT_RSP_DELETE_PROGRESS:
|
||||||
|
ret = parse_del_all_users_progress_report (msg_resp, resp);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BMKT_RSP_CAPTURE_COMPLETE:
|
||||||
|
resp->result = BMKT_SUCCESS;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BMKT_RSP_ENROLL_READY:
|
||||||
|
resp->result = BMKT_SUCCESS;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BMKT_RSP_ENROLL_REPORT:
|
||||||
|
ret = parse_enroll_report (msg_resp, resp);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BMKT_RSP_ENROLL_OK:
|
||||||
|
resp->complete = 1;
|
||||||
|
ret = parse_enroll_ok (msg_resp, resp);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BMKT_RSP_ID_OK:
|
||||||
|
case BMKT_RSP_VERIFY_OK:
|
||||||
|
ret = parse_auth_ok (msg_resp, resp);
|
||||||
|
resp->complete = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BMKT_RSP_GET_ENROLLED_FINGERS_REPORT:
|
||||||
|
ret = parse_get_enrolled_fingers_report (msg_resp, resp);
|
||||||
|
resp->complete = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BMKT_RSP_DATABASE_CAPACITY_REPORT:
|
||||||
|
resp->complete = 1;
|
||||||
|
ret = parse_db_cap_report (msg_resp, resp);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BMKT_RSP_TEMPLATE_RECORDS_REPORT:
|
||||||
|
ret = parse_get_enrolled_users_report (msg_resp, resp);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BMKT_RSP_QUERY_RESPONSE_COMPLETE:
|
||||||
|
resp->complete = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BMKT_RSP_VERSION_INFO:
|
||||||
|
ret = parse_get_version_report (msg_resp, resp);
|
||||||
|
resp->complete = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BMKT_RSP_POWER_DOWN_READY:
|
||||||
|
resp->complete = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
89
libfprint/drivers/synaptics/bmkt_message.h
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 Synaptics Inc
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
#define BMKT_MESSAGE_HEADER_ID 0xFE
|
||||||
|
#define BMKT_MESSAGE_HEADER_LEN (4)
|
||||||
|
#define BMKT_MESSAGE_CRC32_LEN (4)
|
||||||
|
#define BMKT_MESSAGE_HEADER_ID_FIELD 0
|
||||||
|
#define BMKT_MESSAGE_SEQ_NUM_FIELD 1
|
||||||
|
#define BMKT_MESSAGE_ID_FIELD 2
|
||||||
|
#define BMKT_MESSAGE_PAYLOAD_LEN_FIELD 3
|
||||||
|
#define BMKT_MESSAGE_PAYLOAD_FIELD 4
|
||||||
|
|
||||||
|
// Command messages
|
||||||
|
#define BMKT_CMD_CONTINUOUS_IMAGE_CAPTURE 0x01
|
||||||
|
#define BMKT_CMD_CONTINUOUS_IMAGE_CAPTURE_STOP 0x04
|
||||||
|
#define BMKT_CMD_SENSOR_MODULE_TEST 0x06
|
||||||
|
#define BMKT_CMD_SENSOR_MODULE_TEST_START 0x08
|
||||||
|
#define BMKT_CMD_NEXT_TEST_REPORT_CHUNK 0x0B
|
||||||
|
#define BMKT_CMD_FPS_INIT 0x11
|
||||||
|
#define BMKT_CMD_GET_FPS_MODE 0x21
|
||||||
|
#define BMKT_CMD_SET_SECURITY_LEVEL 0x31
|
||||||
|
#define BMKT_CMD_GET_SECURITY_LEVEL 0x34
|
||||||
|
#define BMKT_CMD_CANCEL_OP 0x41
|
||||||
|
#define BMKT_CMD_ENROLL_USER 0x51
|
||||||
|
#define BMKT_CMD_ENROLL_PAUSE 0x52
|
||||||
|
#define BMKT_CMD_ENROLL_RESUME 0x53
|
||||||
|
#define BMKT_CMD_ID_USER 0x61
|
||||||
|
#define BMKT_CMD_VERIFY_USER 0x65
|
||||||
|
#define BMKT_CMD_GET_TEMPLATE_RECORDS 0x71
|
||||||
|
#define BMKT_CMD_GET_NEXT_QUERY_RESPONSE 0x72
|
||||||
|
#define BMKT_CMD_GET_ENROLLED_FINGERS 0x73
|
||||||
|
#define BMKT_CMD_GET_DATABASE_CAPACITY 0x74
|
||||||
|
#define BMKT_CMD_DEL_USER_FP 0x81
|
||||||
|
#define BMKT_CMD_DEL_FULL_DB 0x84
|
||||||
|
#define BMKT_CMD_REPEAT_LAST_RSP 0x92
|
||||||
|
#define BMKT_CMD_POWER_DOWN_NOTIFY 0xA1
|
||||||
|
#define BMKT_CMD_GET_VERSION 0xB1
|
||||||
|
#define BMKT_CMD_DISABLE_PAIRING 0xC2
|
||||||
|
#define BMKT_CMD_QUERY_PAIRING 0xC5
|
||||||
|
#define BMKT_CMD_SENSOR_STATUS 0xD1
|
||||||
|
#define BMKT_CMD_ID_USER_IN_ORDER 0xE1
|
||||||
|
#define BMKT_CMD_ID_NEXT_USER 0xE3
|
||||||
|
#define BMKT_CMD_VERIFY_USER_IN_ORDER 0xF1
|
||||||
|
#define BMKT_CMD_VERIFY_FINGERS_IN_ORDER 0xF2
|
||||||
|
#define BMKT_CMD_GET_FINAL_RESULT 0xE4
|
||||||
|
|
||||||
|
#define BMKT_EVT_FINGER_REPORT 0x91
|
||||||
|
|
||||||
|
#define BMKT_EVT_FINGER_STATE_NOT_ON_SENSOR 0x00
|
||||||
|
#define BMKT_EVT_FINGER_STATE_ON_SENSOR 0x01
|
||||||
|
|
||||||
|
typedef struct bmkt_msg_resp
|
||||||
|
{
|
||||||
|
uint8_t msg_id;
|
||||||
|
uint8_t seq_num;
|
||||||
|
uint8_t payload_len;
|
||||||
|
uint8_t *payload;
|
||||||
|
int result;
|
||||||
|
} bmkt_msg_resp_t;
|
||||||
|
|
||||||
|
int bmkt_compose_message (uint8_t *cmd,
|
||||||
|
int *cmd_len,
|
||||||
|
uint8_t msg_id,
|
||||||
|
uint8_t seq_num,
|
||||||
|
uint8_t payload_size,
|
||||||
|
const uint8_t *payload);
|
||||||
|
|
||||||
|
int bmkt_parse_message_header (uint8_t *resp_buf,
|
||||||
|
int resp_len,
|
||||||
|
bmkt_msg_resp_t *msg_resp);
|
||||||
|
int bmkt_parse_message_payload (bmkt_msg_resp_t *msg_resp,
|
||||||
|
bmkt_response_t *resp);
|
||||||
485
libfprint/drivers/synaptics/bmkt_response.h
Normal file
@@ -0,0 +1,485 @@
|
|||||||
|
/*
|
||||||
|
* Synaptics MiS Fingerprint Sensor Response Data Interface
|
||||||
|
* Copyright (C) 2019 Synaptics Inc
|
||||||
|
*
|
||||||
|
* 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 "bmkt.h"
|
||||||
|
|
||||||
|
/** List of response message IDs */
|
||||||
|
#define BMKT_RSP_CONTINUOUS_IMAGE_CAPTURE_FAIL 0x02
|
||||||
|
#define BMKT_RSP_CONTINUOUS_IMAGE_CAPTURE_READY 0x03
|
||||||
|
#define BMKT_RSP_CONTINUOUS_IMAGE_CAPTURE_STOPPED 0x05
|
||||||
|
#define BMKT_RSP_SENSOR_MODULE_TEST_READY 0x07
|
||||||
|
#define BMKT_RSP_SENSOR_MODULE_TEST_FAIL 0x09
|
||||||
|
#define BMKT_RSP_SENSOR_MODULE_TEST_REPORT 0x0A
|
||||||
|
#define BMKT_RSP_NEXT_TEST_REPORT_CHUNK 0x0C
|
||||||
|
|
||||||
|
/*! \addtogroup init
|
||||||
|
* Response IDs returned by fingerprint initialization operation
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/** Failed to initialize fingerprint sensor module */
|
||||||
|
#define BMKT_RSP_FPS_INIT_FAIL 0x12
|
||||||
|
/** Successfully initialized fingerprint sensor module */
|
||||||
|
#define BMKT_RSP_FPS_INIT_OK 0x13
|
||||||
|
/*! @} */
|
||||||
|
|
||||||
|
/*! \addtogroup mode
|
||||||
|
* Response IDs returned by get fingerprint mode operation
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/** Failed to get fingerprint sensor module’s current operational mode */
|
||||||
|
#define BMKT_RSP_FPS_MODE_FAIL 0x22
|
||||||
|
/**
|
||||||
|
* BMKT_RSP_FPS_MODE_REPORT:
|
||||||
|
* Response containing the current operational mode of the fingerprint sensor module
|
||||||
|
* <br>Payload data represented in \ref bmkt_fps_mode_resp_t struct
|
||||||
|
*/
|
||||||
|
#define BMKT_RSP_FPS_MODE_REPORT 0x23
|
||||||
|
/*! @} */
|
||||||
|
|
||||||
|
/*! \addtogroup setseclevel
|
||||||
|
* Response IDs returned by set security level operation
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/** Failed to set fingerprint sensor module security level */
|
||||||
|
#define BMKT_RSP_SET_SECURITY_LEVEL_FAIL 0x32
|
||||||
|
/**
|
||||||
|
* BMKT_RSP_SET_SECURITY_LEVEL_REPORT:
|
||||||
|
* Security level of the fingerprint sensor module was set successfully
|
||||||
|
* <br>Contains payload data represented in \ref bmkt_set_sec_level_resp_t struct
|
||||||
|
*/
|
||||||
|
#define BMKT_RSP_SET_SECURITY_LEVEL_REPORT 0x33
|
||||||
|
/*! @} */
|
||||||
|
|
||||||
|
/*! \addtogroup getseclevel
|
||||||
|
* Response IDs returned by get security level operation
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/** Failed to get fingerprint sensor module security level */
|
||||||
|
#define BMKT_RSP_GET_SECURITY_LEVEL_FAIL 0x35
|
||||||
|
/**
|
||||||
|
* BMKT_RSP_GET_SECURITY_LEVEL_REPORT:
|
||||||
|
* Returns the current security level of the fingerprint sensor module
|
||||||
|
* <br>Contains payload data represented in \ref bmkt_set_sec_level_resp_t struct
|
||||||
|
*/
|
||||||
|
#define BMKT_RSP_GET_SECURITY_LEVEL_REPORT 0x36
|
||||||
|
/*! @} */
|
||||||
|
|
||||||
|
/*! \addtogroup cancelop
|
||||||
|
* Response IDs returned by cancel_operation operation
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* BMKT_RSP_CANCEL_OP_OK:
|
||||||
|
* Successfully canceled the current operation and returned
|
||||||
|
* fingerprint sensor module to idle mode
|
||||||
|
*/
|
||||||
|
#define BMKT_RSP_CANCEL_OP_OK 0x42
|
||||||
|
/** Failed to cancel the current operation */
|
||||||
|
#define BMKT_RSP_CANCEL_OP_FAIL 0x43
|
||||||
|
/*! @} */
|
||||||
|
|
||||||
|
/*! \addtogroup enrollment
|
||||||
|
* Response IDs returned by enrollment operation
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* BMKT_RSP_ENROLL_READY:
|
||||||
|
* Fingerprint enrollment session has begun and the user can place
|
||||||
|
* their finger on the sensor
|
||||||
|
*/
|
||||||
|
#define BMKT_RSP_ENROLL_READY 0x54
|
||||||
|
/** Progress of the currently on-going fingerprint enrollment session */
|
||||||
|
#define BMKT_RSP_ENROLL_REPORT 0x55
|
||||||
|
/** Enrollment has been paused */
|
||||||
|
#define BMKT_RSP_ENROLL_PAUSED 0x56
|
||||||
|
/** Enrollment has been resume */
|
||||||
|
#define BMKT_RSP_ENROLL_RESUMED 0x57
|
||||||
|
/** The current enrollment session has encountered an error */
|
||||||
|
#define BMKT_RSP_ENROLL_FAIL 0x58
|
||||||
|
/**
|
||||||
|
* BMKT_RSP_ENROLL_OK:
|
||||||
|
* User has been successfully enrolled into the fingerprint sensor module
|
||||||
|
* <br>Contains payload data represented in \ref bmkt_enroll_resp_t struct
|
||||||
|
*/
|
||||||
|
#define BMKT_RSP_ENROLL_OK 0x59
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BMKT_RSP_CAPTURE_COMPLETE:
|
||||||
|
* Fingerprint image capture is complete and it is safe for the user
|
||||||
|
* to lift their finger off the sensor
|
||||||
|
*/
|
||||||
|
#define BMKT_RSP_CAPTURE_COMPLETE 0x60
|
||||||
|
/*! @} */
|
||||||
|
|
||||||
|
/*! \addtogroup identify
|
||||||
|
* Response IDs returned by identify operation.
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/* Fingerprint identification session has begun */
|
||||||
|
#define BMKT_RSP_ID_READY 0x62
|
||||||
|
/* Identification has failed */
|
||||||
|
#define BMKT_RSP_ID_FAIL 0x63
|
||||||
|
/**
|
||||||
|
* BMKT_RSP_ID_OK:
|
||||||
|
* User has been successfully identified
|
||||||
|
* <br>Contains payload data represented in \ref bmkt_auth_resp struct
|
||||||
|
*/
|
||||||
|
#define BMKT_RSP_ID_OK 0x64
|
||||||
|
/*! @} */
|
||||||
|
|
||||||
|
/*! \addtogroup verify
|
||||||
|
* Response IDs returned by identify operation.
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/** Fingerprint verification session has begun */
|
||||||
|
#define BMKT_RSP_VERIFY_READY 0x66
|
||||||
|
/** Verification has failed */
|
||||||
|
#define BMKT_RSP_VERIFY_FAIL 0x67
|
||||||
|
/**
|
||||||
|
* BMKT_RSP_VERIFY_OK:
|
||||||
|
* User’s identity has been successfully verified
|
||||||
|
* <br>Contains payload data represented in \ref bmkt_auth_resp struct
|
||||||
|
*/
|
||||||
|
#define BMKT_RSP_VERIFY_OK 0x68
|
||||||
|
/*! @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BMKT_RSP_TEMPLATE_RECORDS_REPORT:
|
||||||
|
* Response ID returned by get enrolled users templates record operation
|
||||||
|
* <br>Returns list of template records containing user IDs and corresponding finger IDs
|
||||||
|
* <br>Payload data represented in \ref bmkt_enroll_templates_resp_t struct
|
||||||
|
*/
|
||||||
|
#define BMKT_RSP_TEMPLATE_RECORDS_REPORT 0x75
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BMKT_RSP_QUERY_RESPONSE_COMPLETE:
|
||||||
|
* Response ID returned by get next query response operation
|
||||||
|
* <br>Complete sequence of messages containing the template records query response has been sent
|
||||||
|
*/
|
||||||
|
#define BMKT_RSP_QUERY_RESPONSE_COMPLETE 0x76
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BMKT_RSP_GET_ENROLLED_FINGERS_REPORT:
|
||||||
|
* Response ID returned by get enrolled fingers operation
|
||||||
|
* <br> Returns list of IDs of enrolled fingers for a specific user,
|
||||||
|
* along with template record status corresponding to each enrolled finger
|
||||||
|
* <br>Contains payload data represented in \ref bmkt_enrolled_fingers_resp_t struct
|
||||||
|
*/
|
||||||
|
#define BMKT_RSP_GET_ENROLLED_FINGERS_REPORT 0x77
|
||||||
|
|
||||||
|
/*! \addtogroup dbcapacity
|
||||||
|
* Response IDs returned by get database capacity operation
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* BMKT_RSP_DATABASE_CAPACITY_REPORT:
|
||||||
|
* Response specifying total capacity of fingerprint template database and
|
||||||
|
* how much free capacity is remaining along with how many templates are corrupted and
|
||||||
|
* how many bad (permanently unusable) storage slots are there.
|
||||||
|
* <br>Payload data represented in \ref bmkt_get_db_capacity_resp_t struct
|
||||||
|
*/
|
||||||
|
#define BMKT_RSP_DATABASE_CAPACITY_REPORT 0x78
|
||||||
|
/** Failed to execute database query */
|
||||||
|
#define BMKT_RSP_QUERY_FAIL 0x79
|
||||||
|
/*! @} */
|
||||||
|
|
||||||
|
/*! \addtogroup deluser
|
||||||
|
* Response IDs returned by delete fingerprint of specific user operation
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/** Failed to delete a user’s fingerprint template from the database */
|
||||||
|
#define BMKT_RSP_DEL_USER_FP_FAIL 0x82
|
||||||
|
/**
|
||||||
|
* BMKT_RSP_DEL_USER_FP_OK:
|
||||||
|
* Fingerprint template successfully deleted from the database.
|
||||||
|
* Returns the user ID and finger ID deleted. If value of finger ID is set equal to 0,
|
||||||
|
* then all fingerprint templates for that user have been deleted from the database
|
||||||
|
* <br>Payload data represented in \ref bmkt_del_user_resp_t struct
|
||||||
|
*/
|
||||||
|
#define BMKT_RSP_DEL_USER_FP_OK 0x83
|
||||||
|
/*! @} */
|
||||||
|
|
||||||
|
/*! \addtogroup delfulldb
|
||||||
|
* Response IDs returned by delete entire fingerprint template DB operation
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/** Failed to erase entire fingerprint template database */
|
||||||
|
#define BMKT_RSP_DEL_FULL_DB_FAIL 0x85
|
||||||
|
/** Successfully erased entire fingerprint template database */
|
||||||
|
#define BMKT_RSP_DEL_FULL_DB_OK 0x86
|
||||||
|
/**
|
||||||
|
* BMKT_RSP_DELETE_PROGRESS:
|
||||||
|
* Notify progress made during the on-going deletion of the full template database
|
||||||
|
* <br>Payload data represented in \ref bmkt_del_all_users_resp_t struct
|
||||||
|
*/
|
||||||
|
#define BMKT_RSP_DELETE_PROGRESS 0x87
|
||||||
|
/*! @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BMKT_RSP_REPEAT_LAST_BMKT_RSP_FAIL:
|
||||||
|
* Response ID returned by repeate last response operation
|
||||||
|
* <br>Failed to retrieve and re-send last response
|
||||||
|
*/
|
||||||
|
#define BMKT_RSP_REPEAT_LAST_BMKT_RSP_FAIL 0x93
|
||||||
|
|
||||||
|
/*! \addtogroup pwrdwn
|
||||||
|
* Response IDs returned by power down notify operation
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/** Fingerprint sensor module is ready to be powered down */
|
||||||
|
#define BMKT_RSP_POWER_DOWN_READY 0xA2
|
||||||
|
/** Failed to go into power down mode */
|
||||||
|
#define BMKT_RSP_POWER_DOWN_FAIL 0xA3
|
||||||
|
/*! @} */
|
||||||
|
|
||||||
|
/*! \addtogroup versioninfo
|
||||||
|
* Response IDs returned by get version operation
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* BMKT_RSP_VERSION_INFO:
|
||||||
|
* System version information of the fingerprint sensor module
|
||||||
|
* <br>Payload data represented in \ref bmkt_get_version_resp_t struct
|
||||||
|
*/
|
||||||
|
#define BMKT_RSP_VERSION_INFO 0xB2
|
||||||
|
/* Failed to retrieve and send last response */
|
||||||
|
#define BMKT_RSP_GET_VERSION_FAIL 0xB3
|
||||||
|
/*! @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BMKT_RSP_GENERAL_ERROR:
|
||||||
|
* Not tied to a specific command-response session.
|
||||||
|
* <br>Could be caused by corrupt or truncated command message
|
||||||
|
*/
|
||||||
|
#define BMKT_RSP_GENERAL_ERROR 0xC1
|
||||||
|
#define BMKT_RSP_DISABLE_PAIRING_FAIL 0xC3
|
||||||
|
#define BMKT_RSP_DISABLE_PAIRING_OK 0xC4
|
||||||
|
#define BMKT_RSP_QUERY_PAIRING_FAIL 0xC6
|
||||||
|
#define BMKT_RSP_SENSOR_PAIRING_REPORT 0xC7
|
||||||
|
|
||||||
|
/*! \addtogroup versioninfo
|
||||||
|
* Response IDs returned by get sensor module status operation
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* BMKT_RSP_SENSOR_STATUS_REPORT:
|
||||||
|
* Response returning the current status of the sensor module
|
||||||
|
* <br>Payload data represented in bmkt_XXX struct
|
||||||
|
*/
|
||||||
|
#define BMKT_RSP_SENSOR_STATUS_REPORT 0xD2
|
||||||
|
/** Failed to retrieve sensor status */
|
||||||
|
#define BMKT_RSP_SENSOR_STATUS_FAIL 0xD3
|
||||||
|
/*! @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BMKT_RSP_SEND_NEXT_USER_ID:
|
||||||
|
* Response ID returned by identify user in order operation
|
||||||
|
* <br>Notify to send the next batch of user IDs in the priority list
|
||||||
|
*/
|
||||||
|
#define BMKT_RSP_SEND_NEXT_USER_ID 0xE2
|
||||||
|
/**
|
||||||
|
* BMKT_RSP_RETRIEVE_FINAL_RESULT_FAIL:
|
||||||
|
* Response IDs returned by retrieve final result operation
|
||||||
|
* <br>Failed to retrieve and re-send cached final result
|
||||||
|
*/
|
||||||
|
#define BMKT_RSP_RETRIEVE_FINAL_RESULT_FAIL 0xE5
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Response payload data structure returned by sensor initialization operation.
|
||||||
|
*/
|
||||||
|
typedef struct bmkt_init_resp
|
||||||
|
{
|
||||||
|
uint8_t finger_presence; /**< Indicates finger existence on the sensor during startup */
|
||||||
|
} bmkt_init_resp_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bmkt_enroll_resp:
|
||||||
|
* Response payload data structure returned by enrollment operation.
|
||||||
|
*/
|
||||||
|
typedef struct bmkt_enroll_resp
|
||||||
|
{
|
||||||
|
int progress; /**< Shows current progress stutus [0-100] */
|
||||||
|
uint8_t finger_id; /**< User's finger id [1-10] */
|
||||||
|
uint8_t user_id[BMKT_MAX_USER_ID_LEN]; /**< User name to be enrolled */
|
||||||
|
} bmkt_enroll_resp_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bmkt_auth_resp:
|
||||||
|
* Response payload data structure returned by identify and verify operations.
|
||||||
|
*/
|
||||||
|
struct bmkt_auth_resp
|
||||||
|
{
|
||||||
|
double match_result; /**< match result returned by matcher */
|
||||||
|
uint8_t finger_id; /**< Matched templates's finger id */
|
||||||
|
uint8_t user_id[BMKT_MAX_USER_ID_LEN]; /**< Matched template's user id */
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct bmkt_auth_resp bmkt_verify_resp_t; /**< Returned by verify */
|
||||||
|
typedef struct bmkt_auth_resp bmkt_identify_resp_t; /**< Returned by identify */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bmkt_fps_mode_resp:
|
||||||
|
* Response payload data structure returned by get fingerprint mode operation.
|
||||||
|
*/
|
||||||
|
typedef struct bmkt_fps_mode_resp
|
||||||
|
{
|
||||||
|
uint8_t mode; /**< One of the Level I bmkt_mode_t values */
|
||||||
|
uint8_t level2_mode; /**< One of the Level II bmkt_mode_level2_t values */
|
||||||
|
uint8_t cmd_id; /**< Message ID of command being executed when bmkt_get_fps_mode was called */
|
||||||
|
uint8_t finger_presence; /**< Finger presence status value finger on sensor 1 / finger not on sensor 0 */
|
||||||
|
} bmkt_fps_mode_resp_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bmkt_get_version_resp:
|
||||||
|
* Response payload data structure returned by get version operation.
|
||||||
|
*/
|
||||||
|
typedef struct bmkt_get_version_resp
|
||||||
|
{
|
||||||
|
uint8_t part[BMKT_PART_NUM_LEN]; /**< Software Part Number */
|
||||||
|
uint8_t year; /**< Software Version Year */
|
||||||
|
uint8_t week; /**< Software Version Week */
|
||||||
|
uint8_t patch; /**< Software Version Patch Level */
|
||||||
|
uint8_t supplier_id[BMKT_SUPPLIER_ID_LEN]; /**< Software Supplier Identification */
|
||||||
|
} bmkt_get_version_resp_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bmkt_get_db_capacity_resp:
|
||||||
|
* Response payload data structure returned by get DB capacity operation.
|
||||||
|
*/
|
||||||
|
typedef struct bmkt_get_db_capacity_resp
|
||||||
|
{
|
||||||
|
uint8_t total; /**< Total Available Capacity: Total number of template records that can be stored */
|
||||||
|
uint8_t empty; /**< Free Capacity: Number of template records that can still be stored */
|
||||||
|
uint8_t bad_slots; /**< Number of bad template storage slots */
|
||||||
|
uint8_t corrupt_templates; /**< Number of corrupt templates */
|
||||||
|
} bmkt_get_db_capacity_resp_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bmkt_sec_level:
|
||||||
|
* Security level values.
|
||||||
|
*/
|
||||||
|
typedef enum bmkt_sec_level {
|
||||||
|
BMKT_SECURITY_LEVEL_LOW = 0x10,
|
||||||
|
BMKT_SECURITY_LEVEL_MEDIUM = 0x40,
|
||||||
|
BMKT_SECURITY_LEVEL_HIGH = 0x60,
|
||||||
|
} bmkt_sec_level_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bmkt_set_sec_level_resp:
|
||||||
|
* Response payload data structure returned by get/set security level operations.
|
||||||
|
*/
|
||||||
|
typedef struct bmkt_set_sec_level_resp
|
||||||
|
{
|
||||||
|
bmkt_sec_level_t sec_level; /**< One of the bmkt_sec_level_t values */
|
||||||
|
} bmkt_set_sec_level_resp_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bmkt_del_all_users_resp:
|
||||||
|
* Response payload data structure returned by delete all enrolled users operation.
|
||||||
|
*/
|
||||||
|
typedef struct bmkt_del_all_users_resp
|
||||||
|
{
|
||||||
|
int progress; /**< Progress indicator as a percentage */
|
||||||
|
} bmkt_del_all_users_resp_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bmkt_del_user_resp:
|
||||||
|
* Response payload data structure returned by delete enrolled user operation.
|
||||||
|
*/
|
||||||
|
typedef struct bmkt_del_user_resp
|
||||||
|
{
|
||||||
|
int progress; /**< Progress indicator as a percentage */
|
||||||
|
} bmkt_del_user_resp_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bmkt_enroll_template:
|
||||||
|
* Structure of enrolled users template record data.
|
||||||
|
*/
|
||||||
|
typedef struct bmkt_enroll_template
|
||||||
|
{
|
||||||
|
uint8_t user_id_len; /**< Length of user_id string */
|
||||||
|
uint8_t template_status; /**< Template record status */
|
||||||
|
uint8_t finger_id; /**< ID of enrolled finger */
|
||||||
|
uint8_t user_id[BMKT_MAX_USER_ID_LEN + 1]; /**< Name of the enrolled user */
|
||||||
|
} bmkt_enroll_template_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bmkt_enroll_templates_resp:
|
||||||
|
* Response payload data structure returned by get enrolled user list operation.
|
||||||
|
*/
|
||||||
|
typedef struct bmkt_enroll_templates_resp
|
||||||
|
{
|
||||||
|
uint8_t total_query_messages; /**< Total query response messages */
|
||||||
|
uint8_t query_sequence; /**< Query response sequence number */
|
||||||
|
bmkt_enroll_template_t templates[BMKT_MAX_NUM_TEMPLATES_INTERNAL_FLASH]; /**< Enrolled user template records list */
|
||||||
|
} bmkt_enroll_templates_resp_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bmkt_enrolled_fingers:
|
||||||
|
* Structure of template record status corresponding to each enrolled finger.
|
||||||
|
*/
|
||||||
|
typedef struct bmkt_enrolled_fingers
|
||||||
|
{
|
||||||
|
uint8_t finger_id; /**< ID of enrolled finger */
|
||||||
|
uint8_t template_status; /**< Template record status of finger_id */
|
||||||
|
} bmkt_enrolled_fingers_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bmkt_enrolled_fingers_resp:
|
||||||
|
* Response payload data structure returned by get enrolled fingers operation.
|
||||||
|
*/
|
||||||
|
typedef struct bmkt_enrolled_fingers_resp
|
||||||
|
{
|
||||||
|
bmkt_enrolled_fingers_t fingers[10]; /**< List of enroled fingers, max number of supported fingers per user is 10 */
|
||||||
|
} bmkt_enrolled_fingers_resp_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bmkt_response_data_t:
|
||||||
|
* Union combining all response payload data types.
|
||||||
|
*/
|
||||||
|
typedef union
|
||||||
|
{
|
||||||
|
bmkt_init_resp_t init_resp;
|
||||||
|
bmkt_enroll_resp_t enroll_resp;
|
||||||
|
bmkt_verify_resp_t verify_resp;
|
||||||
|
bmkt_identify_resp_t id_resp;
|
||||||
|
bmkt_fps_mode_resp_t fps_mode_resp;
|
||||||
|
bmkt_get_version_resp_t get_version_resp;
|
||||||
|
bmkt_get_db_capacity_resp_t db_cap_resp;
|
||||||
|
bmkt_set_sec_level_resp_t sec_level_resp;
|
||||||
|
bmkt_del_all_users_resp_t del_all_users_resp;
|
||||||
|
bmkt_enroll_templates_resp_t enroll_templates_resp;
|
||||||
|
bmkt_del_user_resp_t del_user_resp;
|
||||||
|
bmkt_enrolled_fingers_resp_t enrolled_fingers_resp;
|
||||||
|
} bmkt_response_data_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bmkt_response:
|
||||||
|
* Structure to abstract different response structure types in one API
|
||||||
|
* to be used in bmkt_resp_cb_t callback function.
|
||||||
|
*/
|
||||||
|
typedef struct bmkt_response
|
||||||
|
{
|
||||||
|
int response_id; /**< Response message ID, one of th BMKT_RSP_XXX */
|
||||||
|
int result; /**< Operation execution result code */
|
||||||
|
int complete; /**< Operation completion status 1: complete / 0: not completed */
|
||||||
|
bmkt_response_data_t response; /**< Operation specific response union */
|
||||||
|
} bmkt_response_t;
|
||||||
85
libfprint/drivers/synaptics/sensor.h
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 Synaptics Inc
|
||||||
|
*
|
||||||
|
* 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 "usb_transport.h"
|
||||||
|
#define BMKT_MAX_PENDING_SESSIONS 2
|
||||||
|
|
||||||
|
typedef enum bmkt_sensor_state {
|
||||||
|
BMKT_SENSOR_STATE_UNINIT = 0,
|
||||||
|
BMKT_SENSOR_STATE_IDLE,
|
||||||
|
BMKT_SENSOR_STATE_INIT,
|
||||||
|
BMKT_SENSOR_STATE_EXIT,
|
||||||
|
} bmkt_sensor_state_t;
|
||||||
|
|
||||||
|
typedef struct bmkt_sensor_drv bmkt_sensor_drv_t;
|
||||||
|
|
||||||
|
typedef struct bmkt_sensor_version
|
||||||
|
{
|
||||||
|
uint32_t build_time;
|
||||||
|
uint32_t build_num;
|
||||||
|
uint8_t version_major;
|
||||||
|
uint8_t version_minor;
|
||||||
|
uint8_t target;
|
||||||
|
uint8_t product;
|
||||||
|
uint8_t silicon_rev;
|
||||||
|
uint8_t formal_release;
|
||||||
|
uint8_t platform;
|
||||||
|
uint8_t patch;
|
||||||
|
uint8_t serial_number[6];
|
||||||
|
uint16_t security;
|
||||||
|
uint8_t iface;
|
||||||
|
uint8_t device_type;
|
||||||
|
} bmkt_sensor_version_t;
|
||||||
|
|
||||||
|
typedef struct bmkt_sensor
|
||||||
|
{
|
||||||
|
bmkt_usb_transport_t usb_xport;
|
||||||
|
bmkt_sensor_version_t version;
|
||||||
|
bmkt_session_ctx_t pending_sessions[BMKT_MAX_PENDING_SESSIONS];
|
||||||
|
int empty_session_idx;
|
||||||
|
int flags;
|
||||||
|
int seq_num;
|
||||||
|
bmkt_sensor_state_t sensor_state;
|
||||||
|
bmkt_event_cb_t finger_event_cb;
|
||||||
|
void *finger_cb_ctx;
|
||||||
|
bmkt_general_error_cb_t gen_err_cb;
|
||||||
|
void *gen_err_cb_ctx;
|
||||||
|
bmkt_op_state_t op_state;
|
||||||
|
} bmkt_sensor_t;
|
||||||
|
|
||||||
|
int bmkt_sensor_open (bmkt_sensor_t *sensor,
|
||||||
|
bmkt_general_error_cb_t err_cb,
|
||||||
|
void *err_cb_ctx);
|
||||||
|
int bmkt_sensor_close (bmkt_sensor_t *sensor);
|
||||||
|
|
||||||
|
int bmkt_sensor_init_fps (bmkt_sensor_t *sensor);
|
||||||
|
|
||||||
|
int bmkt_sensor_send_message (bmkt_sensor_t *sensor,
|
||||||
|
uint8_t msg_id,
|
||||||
|
uint8_t payload_size,
|
||||||
|
uint8_t *payload,
|
||||||
|
bmkt_resp_cb_t resp_cb,
|
||||||
|
void *resp_data);
|
||||||
|
int bmkt_sensor_handle_response (bmkt_sensor_t *sensor,
|
||||||
|
uint8_t *resp_buf,
|
||||||
|
int resp_len,
|
||||||
|
bmkt_msg_resp_t *msg_resp);
|
||||||
|
|
||||||
|
int bmkt_sensor_send_async_read_command (bmkt_sensor_t *sensor);
|
||||||
1214
libfprint/drivers/synaptics/synaptics.c
Normal file
125
libfprint/drivers/synaptics/synaptics.h
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 Synaptics Inc
|
||||||
|
*
|
||||||
|
* 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"
|
||||||
|
|
||||||
|
#define SYNAPTICS_VENDOR_ID 0x06cb
|
||||||
|
|
||||||
|
G_DECLARE_FINAL_TYPE (FpiDeviceSynaptics, fpi_device_synaptics, FPI, DEVICE_SYNAPTICS, FpDevice)
|
||||||
|
|
||||||
|
|
||||||
|
#define MAX_TRANSFER_LEN 263 + 1 /* SPI Header */ + 2 /* VCSFW header */
|
||||||
|
|
||||||
|
#define USB_EP_REQUEST 0x01
|
||||||
|
#define USB_EP_REPLY 0x81
|
||||||
|
#define USB_EP_FINGERPRINT 0x82
|
||||||
|
#define USB_EP_INTERRUPT 0x83
|
||||||
|
|
||||||
|
#define USB_ASYNC_MESSAGE_PENDING 0x4
|
||||||
|
#define USB_INTERRUPT_DATA_SIZE 7
|
||||||
|
|
||||||
|
#define SENSOR_CMD_GET_VERSION 1
|
||||||
|
#define SENSOR_CMD_ACE_COMMAND 167
|
||||||
|
#define SENSOR_CMD_ASYNCMSG_READ 168
|
||||||
|
|
||||||
|
#define SENSOR_FW_CMD_HEADER_LEN 1
|
||||||
|
#define SENSOR_FW_REPLY_HEADER_LEN 2
|
||||||
|
|
||||||
|
|
||||||
|
/* Number of enroll stages */
|
||||||
|
#define ENROLL_SAMPLES 8
|
||||||
|
|
||||||
|
|
||||||
|
#define SYNAPTICS_DRIVER_FULLNAME "Synaptics Sensors"
|
||||||
|
#include "bmkt.h"
|
||||||
|
#include "bmkt_response.h"
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct bmkt_sensor_version
|
||||||
|
{
|
||||||
|
uint32_t build_time;
|
||||||
|
uint32_t build_num;
|
||||||
|
uint8_t version_major;
|
||||||
|
uint8_t version_minor;
|
||||||
|
uint8_t target;
|
||||||
|
uint8_t product;
|
||||||
|
uint8_t silicon_rev;
|
||||||
|
uint8_t formal_release;
|
||||||
|
uint8_t platform;
|
||||||
|
uint8_t patch;
|
||||||
|
uint8_t serial_number[6];
|
||||||
|
uint16_t security;
|
||||||
|
uint8_t iface;
|
||||||
|
uint8_t device_type;
|
||||||
|
} bmkt_sensor_version_t;
|
||||||
|
|
||||||
|
|
||||||
|
struct syna_enroll_resp_data
|
||||||
|
{
|
||||||
|
int progress;
|
||||||
|
};
|
||||||
|
typedef enum syna_state {
|
||||||
|
SYNA_STATE_UNINIT = 0,
|
||||||
|
SYNA_STATE_IDLE,
|
||||||
|
SYNA_STATE_ENROLL,
|
||||||
|
SYNA_STATE_IDENTIFY,
|
||||||
|
SYNA_STATE_IDENTIFY_DELAY_RESULT,
|
||||||
|
SYNA_STATE_VERIFY,
|
||||||
|
SYNA_STATE_VERIFY_DELAY_RESULT,
|
||||||
|
SYNA_STATE_DELETE,
|
||||||
|
} syna_state_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SYNAPTICS_CMD_SEND_PENDING = 0,
|
||||||
|
SYNAPTICS_CMD_GET_RESP,
|
||||||
|
SYNAPTICS_CMD_WAIT_INTERRUPT,
|
||||||
|
SYNAPTICS_CMD_SEND_ASYNC,
|
||||||
|
SYNAPTICS_CMD_RESTART,
|
||||||
|
SYNAPTICS_CMD_NUM_STATES,
|
||||||
|
} SynapticsCmdState;
|
||||||
|
|
||||||
|
|
||||||
|
typedef void (*SynCmdMsgCallback) (FpiDeviceSynaptics *self,
|
||||||
|
bmkt_response_t *resp,
|
||||||
|
GError *error);
|
||||||
|
|
||||||
|
struct _FpiDeviceSynaptics
|
||||||
|
{
|
||||||
|
FpDevice parent;
|
||||||
|
|
||||||
|
guint8 cmd_seq_num;
|
||||||
|
guint8 last_seq_num;
|
||||||
|
FpiSsm *cmd_ssm;
|
||||||
|
FpiUsbTransfer *cmd_pending_transfer;
|
||||||
|
gboolean cmd_complete_on_removal;
|
||||||
|
|
||||||
|
bmkt_sensor_version_t mis_version;
|
||||||
|
|
||||||
|
GCancellable *interrupt_cancellable;
|
||||||
|
|
||||||
|
gint enroll_stage;
|
||||||
|
gboolean finger_on_sensor;
|
||||||
|
GPtrArray *list_result;
|
||||||
|
|
||||||
|
|
||||||
|
struct syna_enroll_resp_data enroll_resp_data;
|
||||||
|
syna_state_t state;
|
||||||
|
};
|
||||||
67
libfprint/drivers/upek_proto.c
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* LGPL CRC code copied from GStreamer-0.10.10:
|
||||||
|
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||||
|
* Copyright (C) 2004,2006 Thomas Vander Stichele <thomas at apestaart dot 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; version
|
||||||
|
* 2.1 of the License.
|
||||||
|
*
|
||||||
|
* 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 "upek_proto.h"
|
||||||
|
|
||||||
|
static const uint16_t crc_table[256] = {
|
||||||
|
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
|
||||||
|
0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
|
||||||
|
0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
|
||||||
|
0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
|
||||||
|
0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
|
||||||
|
0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
|
||||||
|
0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
|
||||||
|
0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
|
||||||
|
0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
|
||||||
|
0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
|
||||||
|
0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
|
||||||
|
0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
|
||||||
|
0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
|
||||||
|
0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
|
||||||
|
0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
|
||||||
|
0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
|
||||||
|
0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
|
||||||
|
0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
|
||||||
|
0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
|
||||||
|
0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
|
||||||
|
0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
|
||||||
|
0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
|
||||||
|
0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
|
||||||
|
0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
|
||||||
|
0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
|
||||||
|
0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
|
||||||
|
0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
|
||||||
|
0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
|
||||||
|
0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
|
||||||
|
0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
|
||||||
|
0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
|
||||||
|
0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
|
||||||
|
};
|
||||||
|
|
||||||
|
uint16_t
|
||||||
|
udf_crc (unsigned char *buffer, size_t size)
|
||||||
|
{
|
||||||
|
uint16_t crc = 0;
|
||||||
|
|
||||||
|
while (size--)
|
||||||
|
crc = (uint16_t) ((crc << 8) ^
|
||||||
|
crc_table[((crc >> 8) & 0x00ff) ^ *buffer++]);
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
25
libfprint/drivers/upek_proto.h
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* LGPL CRC code copied from GStreamer-0.10.10:
|
||||||
|
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||||
|
* Copyright (C) 2004,2006 Thomas Vander Stichele <thomas at apestaart dot 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; version
|
||||||
|
* 2.1 of the License.
|
||||||
|
*
|
||||||
|
* 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 <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
uint16_t udf_crc (unsigned char *buffer,
|
||||||
|
size_t size);
|
||||||
@@ -27,9 +27,10 @@
|
|||||||
#define IMG_WIDTH_1000 288
|
#define IMG_WIDTH_1000 288
|
||||||
#define IMG_WIDTH_1001 216
|
#define IMG_WIDTH_1001 216
|
||||||
|
|
||||||
struct sonly_regwrite {
|
struct sonly_regwrite
|
||||||
uint8_t reg;
|
{
|
||||||
uint8_t value;
|
guint8 reg;
|
||||||
|
guint8 value;
|
||||||
};
|
};
|
||||||
|
|
||||||
/***** AWAIT FINGER *****/
|
/***** AWAIT FINGER *****/
|
||||||
|
|||||||
@@ -23,13 +23,16 @@
|
|||||||
#include "drivers_api.h"
|
#include "drivers_api.h"
|
||||||
#include "upektc.h"
|
#include "upektc.h"
|
||||||
|
|
||||||
#define UPEKTC_EP_IN (2 | LIBUSB_ENDPOINT_IN)
|
#define UPEKTC_EP_IN (2 | FPI_USB_ENDPOINT_IN)
|
||||||
#define UPEKTC_EP_OUT (3 | LIBUSB_ENDPOINT_OUT)
|
#define UPEKTC_EP_OUT (3 | FPI_USB_ENDPOINT_OUT)
|
||||||
#define UPEKET_EP_IN (1 | LIBUSB_ENDPOINT_IN)
|
#define UPEKET_EP_IN (1 | FPI_USB_ENDPOINT_IN)
|
||||||
#define UPEKET_EP_OUT (2 | LIBUSB_ENDPOINT_OUT)
|
#define UPEKET_EP_OUT (2 | FPI_USB_ENDPOINT_OUT)
|
||||||
#define BULK_TIMEOUT 4000
|
#define BULK_TIMEOUT 4000
|
||||||
|
|
||||||
struct upektc_dev {
|
struct _FpiDeviceUpektc
|
||||||
|
{
|
||||||
|
FpImageDevice parent;
|
||||||
|
|
||||||
gboolean deactivating;
|
gboolean deactivating;
|
||||||
const struct setup_cmd *setup_commands;
|
const struct setup_cmd *setup_commands;
|
||||||
size_t setup_commands_len;
|
size_t setup_commands_len;
|
||||||
@@ -38,15 +41,19 @@ struct upektc_dev {
|
|||||||
int init_idx;
|
int init_idx;
|
||||||
int sum_threshold;
|
int sum_threshold;
|
||||||
};
|
};
|
||||||
|
G_DECLARE_FINAL_TYPE (FpiDeviceUpektc, fpi_device_upektc, FPI, DEVICE_UPEKTC,
|
||||||
|
FpImageDevice);
|
||||||
|
G_DEFINE_TYPE (FpiDeviceUpektc, fpi_device_upektc, FP_TYPE_IMAGE_DEVICE);
|
||||||
|
|
||||||
enum upektc_driver_data {
|
enum upektc_driver_data {
|
||||||
UPEKTC_2015,
|
UPEKTC_2015,
|
||||||
UPEKTC_3001,
|
UPEKTC_3001,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void start_capture(struct fp_img_dev *dev);
|
static void start_capture (FpImageDevice *dev);
|
||||||
static void complete_deactivation(struct fp_img_dev *dev);
|
static void complete_deactivation (FpImageDevice *dev,
|
||||||
static void start_finger_detection(struct fp_img_dev *dev);
|
GError *error);
|
||||||
|
static void start_finger_detection (FpImageDevice *dev);
|
||||||
|
|
||||||
/****** INITIALIZATION/DEINITIALIZATION ******/
|
/****** INITIALIZATION/DEINITIALIZATION ******/
|
||||||
|
|
||||||
@@ -56,221 +63,189 @@ enum activate_states {
|
|||||||
ACTIVATE_NUM_STATES,
|
ACTIVATE_NUM_STATES,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void upektc_next_init_cmd(struct fpi_ssm *ssm)
|
static void
|
||||||
|
upektc_next_init_cmd (FpiSsm *ssm,
|
||||||
|
FpImageDevice *dev)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
|
||||||
struct upektc_dev *upekdev = fpi_imgdev_get_user_data(dev);
|
|
||||||
|
|
||||||
upekdev->init_idx += 1;
|
self->init_idx += 1;
|
||||||
if (upekdev->init_idx == upekdev->setup_commands_len)
|
if (self->init_idx == self->setup_commands_len)
|
||||||
fpi_ssm_mark_completed (ssm);
|
fpi_ssm_mark_completed (ssm);
|
||||||
else
|
else
|
||||||
fpi_ssm_jump_to_state (ssm, WRITE_INIT);
|
fpi_ssm_jump_to_state (ssm, WRITE_INIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void write_init_cb(struct libusb_transfer *transfer)
|
static void
|
||||||
|
write_init_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
|
gpointer user_data, GError *error)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
|
||||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
|
||||||
struct upektc_dev *upekdev = fpi_imgdev_get_user_data(dev);
|
|
||||||
|
|
||||||
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
|
if (!error)
|
||||||
(transfer->length == transfer->actual_length)) {
|
{
|
||||||
if (upekdev->setup_commands[upekdev->init_idx].response_len)
|
if (self->setup_commands[self->init_idx].response_len)
|
||||||
fpi_ssm_next_state(ssm);
|
fpi_ssm_next_state (transfer->ssm);
|
||||||
else
|
else
|
||||||
upektc_next_init_cmd(ssm);
|
upektc_next_init_cmd (transfer->ssm, dev);
|
||||||
} else {
|
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
|
||||||
}
|
}
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void read_init_data_cb(struct libusb_transfer *transfer)
|
|
||||||
{
|
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
|
||||||
|
|
||||||
if (transfer->status == LIBUSB_TRANSFER_COMPLETED)
|
|
||||||
upektc_next_init_cmd(ssm);
|
|
||||||
else
|
else
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
{
|
||||||
g_free(transfer->buffer);
|
fpi_ssm_mark_failed (transfer->ssm, error);
|
||||||
libusb_free_transfer(transfer);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void activate_run_state(struct fpi_ssm *ssm)
|
static void
|
||||||
|
read_init_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
|
gpointer user_data, GError *error)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
|
||||||
struct upektc_dev *upekdev = fpi_imgdev_get_user_data(dev);
|
|
||||||
int r;
|
|
||||||
|
|
||||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
if (!error)
|
||||||
|
upektc_next_init_cmd (transfer->ssm, dev);
|
||||||
|
else
|
||||||
|
fpi_ssm_mark_failed (transfer->ssm, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
activate_run_state (FpiSsm *ssm, FpDevice *dev)
|
||||||
|
{
|
||||||
|
FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
|
||||||
|
|
||||||
|
switch (fpi_ssm_get_cur_state (ssm))
|
||||||
|
{
|
||||||
case WRITE_INIT:
|
case WRITE_INIT:
|
||||||
{
|
{
|
||||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
|
||||||
if (!transfer) {
|
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
fpi_usb_transfer_fill_bulk_full (transfer,
|
||||||
return;
|
self->ep_out,
|
||||||
}
|
(unsigned char *) self->setup_commands[self->init_idx].cmd,
|
||||||
libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), upekdev->ep_out,
|
UPEKTC_CMD_LEN,
|
||||||
(unsigned char*)upekdev->setup_commands[upekdev->init_idx].cmd,
|
NULL);
|
||||||
UPEKTC_CMD_LEN, write_init_cb, ssm, BULK_TIMEOUT);
|
transfer->ssm = ssm;
|
||||||
r = libusb_submit_transfer(transfer);
|
transfer->short_is_error = TRUE;
|
||||||
if (r < 0) {
|
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
||||||
libusb_free_transfer(transfer);
|
write_init_cb, NULL);
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case READ_DATA:
|
case READ_DATA:
|
||||||
{
|
{
|
||||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
|
||||||
unsigned char *data;
|
|
||||||
|
|
||||||
if (!transfer) {
|
fpi_usb_transfer_fill_bulk (transfer,
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
self->ep_in,
|
||||||
break;
|
self->setup_commands[self->init_idx].response_len);
|
||||||
}
|
transfer->ssm = ssm;
|
||||||
|
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
||||||
data = g_malloc(upekdev->setup_commands[upekdev->init_idx].response_len);
|
read_init_data_cb, NULL);
|
||||||
libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), upekdev->ep_in, data,
|
|
||||||
upekdev->setup_commands[upekdev->init_idx].response_len,
|
|
||||||
read_init_data_cb, ssm, BULK_TIMEOUT);
|
|
||||||
|
|
||||||
r = libusb_submit_transfer(transfer);
|
|
||||||
if (r < 0) {
|
|
||||||
g_free(data);
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
fpi_ssm_mark_aborted(ssm, r);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void activate_sm_complete(struct fpi_ssm *ssm)
|
static void
|
||||||
|
activate_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
|
||||||
fp_dbg("status %d", fpi_ssm_get_error(ssm));
|
|
||||||
fpi_imgdev_activate_complete(dev, fpi_ssm_get_error(ssm));
|
|
||||||
|
|
||||||
if (!fpi_ssm_get_error(ssm))
|
fpi_image_device_activate_complete (dev, error);
|
||||||
|
|
||||||
|
if (!error)
|
||||||
start_finger_detection (dev);
|
start_finger_detection (dev);
|
||||||
fpi_ssm_free(ssm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/****** FINGER PRESENCE DETECTION ******/
|
/****** FINGER PRESENCE DETECTION ******/
|
||||||
|
|
||||||
static int finger_present(unsigned char *img, size_t len, int sum_threshold)
|
static int
|
||||||
|
finger_present (unsigned char *img, size_t len, int sum_threshold)
|
||||||
{
|
{
|
||||||
int i, sum;
|
int i, sum;
|
||||||
|
|
||||||
sum = 0;
|
sum = 0;
|
||||||
|
|
||||||
for (i = 0; i < len; i++) {
|
for (i = 0; i < len; i++)
|
||||||
if (img[i] < 160) {
|
if (img[i] < 160)
|
||||||
sum++;
|
sum++;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fp_dbg ("finger_present: sum is %d\n", sum);
|
fp_dbg ("finger_present: sum is %d\n", sum);
|
||||||
return sum < sum_threshold ? 0 : 1;
|
return sum < sum_threshold ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void finger_det_data_cb(struct libusb_transfer *transfer)
|
static void
|
||||||
|
finger_det_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
|
gpointer user_data, GError *error)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = transfer->user_data;
|
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
|
||||||
struct upektc_dev *upekdev = fpi_imgdev_get_user_data(dev);
|
FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
|
||||||
unsigned char *data = transfer->buffer;
|
|
||||||
|
|
||||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
if (error)
|
||||||
fp_dbg("data transfer status %d\n", transfer->status);
|
{
|
||||||
fpi_imgdev_session_error(dev, -EIO);
|
fp_dbg ("data transfer status %s\n", error->message);
|
||||||
goto out;
|
fpi_image_device_session_error (dev, error);
|
||||||
} else if (transfer->length != transfer->actual_length) {
|
return;
|
||||||
fp_dbg("expected %d, got %d bytes", transfer->length,
|
|
||||||
transfer->actual_length);
|
|
||||||
fpi_imgdev_session_error(dev, -EPROTO);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (finger_present(data, IMAGE_SIZE, upekdev->sum_threshold)) {
|
if (finger_present (transfer->buffer, IMAGE_SIZE, self->sum_threshold))
|
||||||
|
{
|
||||||
/* finger present, start capturing */
|
/* finger present, start capturing */
|
||||||
fpi_imgdev_report_finger_status(dev, TRUE);
|
fpi_image_device_report_finger_status (dev, TRUE);
|
||||||
start_capture (dev);
|
start_capture (dev);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/* no finger, poll for a new histogram */
|
/* no finger, poll for a new histogram */
|
||||||
start_finger_detection (dev);
|
start_finger_detection (dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
|
||||||
g_free(data);
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void finger_det_cmd_cb(struct libusb_transfer *t)
|
static void
|
||||||
|
finger_det_cmd_cb (FpiUsbTransfer *t, FpDevice *device,
|
||||||
|
gpointer user_data, GError *error)
|
||||||
{
|
{
|
||||||
struct libusb_transfer *transfer;
|
FpiUsbTransfer *transfer;
|
||||||
unsigned char *data;
|
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
|
||||||
int r;
|
FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
|
||||||
struct fp_img_dev *dev = t->user_data;
|
|
||||||
struct upektc_dev *upekdev = fpi_imgdev_get_user_data(dev);
|
|
||||||
|
|
||||||
if (t->status != LIBUSB_TRANSFER_COMPLETED) {
|
if (error)
|
||||||
fp_dbg("req transfer status %d\n", t->status);
|
|
||||||
fpi_imgdev_session_error(dev, -EIO);
|
|
||||||
goto exit_free_transfer;
|
|
||||||
} else if (t->length != t->actual_length) {
|
|
||||||
fp_dbg("expected %d, sent %d bytes", t->length, t->actual_length);
|
|
||||||
fpi_imgdev_session_error(dev, -EPROTO);
|
|
||||||
goto exit_free_transfer;
|
|
||||||
}
|
|
||||||
|
|
||||||
transfer = libusb_alloc_transfer(0);
|
|
||||||
if (!transfer) {
|
|
||||||
fpi_imgdev_session_error(dev, -ENOMEM);
|
|
||||||
goto exit_free_transfer;
|
|
||||||
}
|
|
||||||
|
|
||||||
data = g_malloc(IMAGE_SIZE);
|
|
||||||
libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), upekdev->ep_in, data, IMAGE_SIZE,
|
|
||||||
finger_det_data_cb, dev, BULK_TIMEOUT);
|
|
||||||
|
|
||||||
r = libusb_submit_transfer(transfer);
|
|
||||||
if (r < 0) {
|
|
||||||
g_free(data);
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
fpi_imgdev_session_error(dev, r);
|
|
||||||
}
|
|
||||||
exit_free_transfer:
|
|
||||||
libusb_free_transfer(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void start_finger_detection(struct fp_img_dev *dev)
|
|
||||||
{
|
{
|
||||||
int r;
|
fp_dbg ("req transfer status %s\n", error->message);
|
||||||
struct upektc_dev *upekdev = fpi_imgdev_get_user_data(dev);
|
fpi_image_device_session_error (dev, error);
|
||||||
struct libusb_transfer *transfer;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
transfer = fpi_usb_transfer_new (device);
|
||||||
|
transfer->short_is_error = TRUE;
|
||||||
|
fpi_usb_transfer_fill_bulk (transfer, self->ep_in,
|
||||||
|
IMAGE_SIZE);
|
||||||
|
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
||||||
|
finger_det_data_cb, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
start_finger_detection (FpImageDevice *dev)
|
||||||
|
{
|
||||||
|
FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
|
||||||
|
FpiUsbTransfer *transfer;
|
||||||
|
|
||||||
G_DEBUG_HERE ();
|
G_DEBUG_HERE ();
|
||||||
|
|
||||||
if (upekdev->deactivating) {
|
if (self->deactivating)
|
||||||
complete_deactivation(dev);
|
{
|
||||||
|
complete_deactivation (dev, NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
transfer = libusb_alloc_transfer(0);
|
transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
|
||||||
if (!transfer) {
|
transfer->short_is_error = TRUE;
|
||||||
fpi_imgdev_session_error(dev, -ENOMEM);
|
fpi_usb_transfer_fill_bulk_full (transfer, self->ep_out,
|
||||||
return;
|
(unsigned char *) scan_cmd,
|
||||||
}
|
UPEKTC_CMD_LEN, NULL);
|
||||||
libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), upekdev->ep_out,
|
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
||||||
(unsigned char *)scan_cmd, UPEKTC_CMD_LEN,
|
finger_det_cmd_cb, NULL);
|
||||||
finger_det_cmd_cb, dev, BULK_TIMEOUT);
|
|
||||||
r = libusb_submit_transfer(transfer);
|
|
||||||
if (r < 0) {
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
fpi_imgdev_session_error(dev, r);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/****** CAPTURE ******/
|
/****** CAPTURE ******/
|
||||||
@@ -281,223 +256,208 @@ enum capture_states {
|
|||||||
CAPTURE_NUM_STATES,
|
CAPTURE_NUM_STATES,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void capture_cmd_cb(struct libusb_transfer *transfer)
|
static void
|
||||||
|
capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
|
gpointer user_data, GError *error)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
FpImageDevice *dev = FP_IMAGE_DEVICE (device);
|
||||||
|
FpImage *img;
|
||||||
|
|
||||||
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
|
if (error)
|
||||||
(transfer->length == transfer->actual_length)) {
|
|
||||||
fpi_ssm_next_state(ssm);
|
|
||||||
} else {
|
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
|
||||||
}
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void capture_read_data_cb(struct libusb_transfer *transfer)
|
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
fp_dbg ("request is not completed, %s", error->message);
|
||||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
fpi_ssm_mark_failed (transfer->ssm, error);
|
||||||
unsigned char *data = transfer->buffer;
|
return;
|
||||||
struct fp_img *img;
|
|
||||||
|
|
||||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
|
||||||
fp_dbg("request is not completed, %d", transfer->status);
|
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
|
||||||
goto out;
|
|
||||||
} else if (transfer->length != transfer->actual_length) {
|
|
||||||
fp_dbg("expected %d, sent %d bytes", transfer->length, transfer->actual_length);
|
|
||||||
fpi_ssm_mark_aborted(ssm, -EPROTO);
|
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
img = fpi_img_new(IMAGE_SIZE);
|
img = fp_image_new (IMAGE_WIDTH, IMAGE_HEIGHT);
|
||||||
memcpy(img->data, data, IMAGE_SIZE);
|
memcpy (img->data, transfer->buffer, IMAGE_SIZE);
|
||||||
fpi_imgdev_image_captured(dev, img);
|
fpi_image_device_image_captured (dev, img);
|
||||||
fpi_imgdev_report_finger_status(dev, FALSE);
|
fpi_image_device_report_finger_status (dev, FALSE);
|
||||||
fpi_ssm_mark_completed(ssm);
|
fpi_ssm_mark_completed (transfer->ssm);
|
||||||
out:
|
|
||||||
g_free(transfer->buffer);
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void capture_run_state(struct fpi_ssm *ssm)
|
static void
|
||||||
|
capture_run_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (_dev);
|
||||||
struct upektc_dev *upekdev = fpi_imgdev_get_user_data(dev);
|
|
||||||
int r;
|
|
||||||
|
|
||||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
switch (fpi_ssm_get_cur_state (ssm))
|
||||||
|
{
|
||||||
case CAPTURE_WRITE_CMD:
|
case CAPTURE_WRITE_CMD:
|
||||||
{
|
{
|
||||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
FpiUsbTransfer *transfer = fpi_usb_transfer_new (_dev);
|
||||||
if (!transfer) {
|
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
fpi_usb_transfer_fill_bulk_full (transfer, self->ep_out,
|
||||||
return;
|
(unsigned char *) scan_cmd,
|
||||||
}
|
UPEKTC_CMD_LEN, NULL);
|
||||||
libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), upekdev->ep_out,
|
transfer->ssm = ssm;
|
||||||
(unsigned char *)scan_cmd, UPEKTC_CMD_LEN,
|
transfer->short_is_error = TRUE;
|
||||||
capture_cmd_cb, ssm, BULK_TIMEOUT);
|
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
||||||
r = libusb_submit_transfer(transfer);
|
fpi_ssm_usb_transfer_cb, NULL);
|
||||||
if (r < 0) {
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CAPTURE_READ_DATA:
|
case CAPTURE_READ_DATA:
|
||||||
{
|
{
|
||||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
FpiUsbTransfer *transfer = fpi_usb_transfer_new (_dev);
|
||||||
unsigned char *data;
|
|
||||||
|
|
||||||
if (!transfer) {
|
fpi_usb_transfer_fill_bulk (transfer, self->ep_in,
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
IMAGE_SIZE);
|
||||||
break;
|
transfer->ssm = ssm;
|
||||||
}
|
transfer->short_is_error = TRUE;
|
||||||
|
fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
|
||||||
data = g_malloc(IMAGE_SIZE);
|
capture_read_data_cb, NULL);
|
||||||
libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), upekdev->ep_in, data, IMAGE_SIZE,
|
|
||||||
capture_read_data_cb, ssm, BULK_TIMEOUT);
|
|
||||||
|
|
||||||
r = libusb_submit_transfer(transfer);
|
|
||||||
if (r < 0) {
|
|
||||||
g_free(data);
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
fpi_ssm_mark_aborted(ssm, r);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
};
|
}
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void capture_sm_complete(struct fpi_ssm *ssm)
|
static void
|
||||||
|
capture_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
|
||||||
struct upektc_dev *upekdev = fpi_imgdev_get_user_data(dev);
|
FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (_dev);
|
||||||
|
|
||||||
fp_dbg ("Capture completed");
|
fp_dbg ("Capture completed");
|
||||||
if (upekdev->deactivating)
|
if (self->deactivating)
|
||||||
complete_deactivation(dev);
|
complete_deactivation (dev, error);
|
||||||
else if (fpi_ssm_get_error(ssm))
|
else if (error)
|
||||||
fpi_imgdev_session_error(dev, fpi_ssm_get_error(ssm));
|
fpi_image_device_session_error (dev, error);
|
||||||
else
|
else
|
||||||
start_finger_detection (dev);
|
start_finger_detection (dev);
|
||||||
fpi_ssm_free(ssm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void start_capture(struct fp_img_dev *dev)
|
static void
|
||||||
|
start_capture (FpImageDevice *dev)
|
||||||
{
|
{
|
||||||
struct upektc_dev *upekdev = fpi_imgdev_get_user_data(dev);
|
FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
|
||||||
struct fpi_ssm *ssm;
|
FpiSsm *ssm;
|
||||||
|
|
||||||
if (upekdev->deactivating) {
|
if (self->deactivating)
|
||||||
complete_deactivation(dev);
|
{
|
||||||
|
complete_deactivation (dev, NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssm = fpi_ssm_new(fpi_imgdev_get_dev(dev), capture_run_state, CAPTURE_NUM_STATES);
|
ssm = fpi_ssm_new (FP_DEVICE (dev), capture_run_state, CAPTURE_NUM_STATES);
|
||||||
G_DEBUG_HERE ();
|
G_DEBUG_HERE ();
|
||||||
fpi_ssm_set_user_data(ssm, dev);
|
|
||||||
fpi_ssm_start (ssm, capture_sm_complete);
|
fpi_ssm_start (ssm, capture_sm_complete);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
static void
|
||||||
|
dev_activate (FpImageDevice *dev)
|
||||||
{
|
{
|
||||||
struct upektc_dev *upekdev = fpi_imgdev_get_user_data(dev);
|
FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
|
||||||
struct fpi_ssm *ssm = fpi_ssm_new(fpi_imgdev_get_dev(dev), activate_run_state,
|
FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), activate_run_state,
|
||||||
ACTIVATE_NUM_STATES);
|
ACTIVATE_NUM_STATES);
|
||||||
fpi_ssm_set_user_data(ssm, dev);
|
|
||||||
upekdev->init_idx = 0;
|
self->init_idx = 0;
|
||||||
fpi_ssm_start (ssm, activate_sm_complete);
|
fpi_ssm_start (ssm, activate_sm_complete);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dev_deactivate(struct fp_img_dev *dev)
|
static void
|
||||||
|
dev_deactivate (FpImageDevice *dev)
|
||||||
{
|
{
|
||||||
struct upektc_dev *upekdev = fpi_imgdev_get_user_data(dev);
|
FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
|
||||||
|
|
||||||
upekdev->deactivating = TRUE;
|
self->deactivating = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void complete_deactivation(struct fp_img_dev *dev)
|
static void
|
||||||
|
complete_deactivation (FpImageDevice *dev, GError *error)
|
||||||
{
|
{
|
||||||
struct upektc_dev *upekdev = fpi_imgdev_get_user_data(dev);
|
FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
|
||||||
|
|
||||||
G_DEBUG_HERE ();
|
G_DEBUG_HERE ();
|
||||||
|
|
||||||
upekdev->deactivating = FALSE;
|
self->deactivating = FALSE;
|
||||||
fpi_imgdev_deactivate_complete(dev);
|
fpi_image_device_deactivate_complete (dev, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
static void
|
||||||
|
dev_init (FpImageDevice *dev)
|
||||||
{
|
{
|
||||||
/* TODO check that device has endpoints we're using */
|
GError *error = NULL;
|
||||||
int r;
|
FpiDeviceUpektc *self = FPI_DEVICE_UPEKTC (dev);
|
||||||
struct upektc_dev *upekdev;
|
guint64 driver_data = fpi_device_get_driver_data (FP_DEVICE (dev));
|
||||||
|
|
||||||
r = libusb_claim_interface(fpi_imgdev_get_usb_dev(dev), 0);
|
/* TODO check that device has endpoints we're using */
|
||||||
if (r < 0) {
|
|
||||||
fp_err("could not claim interface 0: %s", libusb_error_name(r));
|
if (!g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error))
|
||||||
return r;
|
{
|
||||||
|
fpi_image_device_open_complete (dev, error);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
upekdev = g_malloc0(sizeof(struct upektc_dev));
|
switch (driver_data)
|
||||||
fpi_imgdev_set_user_data(dev, upekdev);
|
{
|
||||||
switch (driver_data) {
|
|
||||||
case UPEKTC_2015:
|
case UPEKTC_2015:
|
||||||
upekdev->ep_in = UPEKTC_EP_IN;
|
self->ep_in = UPEKTC_EP_IN;
|
||||||
upekdev->ep_out = UPEKTC_EP_OUT;
|
self->ep_out = UPEKTC_EP_OUT;
|
||||||
upekdev->setup_commands = upektc_setup_commands;
|
self->setup_commands = upektc_setup_commands;
|
||||||
upekdev->setup_commands_len = G_N_ELEMENTS(upektc_setup_commands);
|
self->setup_commands_len = G_N_ELEMENTS (upektc_setup_commands);
|
||||||
upekdev->sum_threshold = UPEKTC_SUM_THRESHOLD;
|
self->sum_threshold = UPEKTC_SUM_THRESHOLD;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case UPEKTC_3001:
|
case UPEKTC_3001:
|
||||||
upekdev->ep_in = UPEKET_EP_IN;
|
self->ep_in = UPEKET_EP_IN;
|
||||||
upekdev->ep_out = UPEKET_EP_OUT;
|
self->ep_out = UPEKET_EP_OUT;
|
||||||
upekdev->setup_commands = upeket_setup_commands;
|
self->setup_commands = upeket_setup_commands;
|
||||||
upekdev->setup_commands_len = G_N_ELEMENTS(upeket_setup_commands);
|
self->setup_commands_len = G_N_ELEMENTS (upeket_setup_commands);
|
||||||
upekdev->sum_threshold = UPEKET_SUM_THRESHOLD;
|
self->sum_threshold = UPEKET_SUM_THRESHOLD;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
fp_err ("Device variant %lu is not known\n", driver_data);
|
fp_err ("Device variant %lu is not known\n", driver_data);
|
||||||
g_free(upekdev);
|
g_assert_not_reached ();
|
||||||
fpi_imgdev_set_user_data(dev, NULL);
|
fpi_image_device_open_complete (dev, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
|
||||||
return -ENODEV;
|
return;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
fpi_imgdev_open_complete(dev, 0);
|
fpi_image_device_open_complete (dev, NULL);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dev_deinit(struct fp_img_dev *dev)
|
static void
|
||||||
|
dev_deinit (FpImageDevice *dev)
|
||||||
{
|
{
|
||||||
void *user_data;
|
GError *error = NULL;
|
||||||
user_data = fpi_imgdev_get_user_data(dev);
|
|
||||||
g_free(user_data);
|
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)),
|
||||||
libusb_release_interface(fpi_imgdev_get_usb_dev(dev), 0);
|
0, 0, &error);
|
||||||
fpi_imgdev_close_complete(dev);
|
fpi_image_device_close_complete (dev, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct usb_id id_table[] = {
|
static const FpIdEntry id_table[] = {
|
||||||
{ .vendor = 0x0483, .product = 0x2015, .driver_data = UPEKTC_2015 },
|
{ .vid = 0x0483, .pid = 0x2015, .driver_data = UPEKTC_2015 },
|
||||||
{ .vendor = 0x147e, .product = 0x3001, .driver_data = UPEKTC_3001 },
|
{ .vid = 0x147e, .pid = 0x3001, .driver_data = UPEKTC_3001 },
|
||||||
{ 0, 0, 0, },
|
{ .vid = 0, .pid = 0, .driver_data = 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fp_img_driver upektc_driver = {
|
static void
|
||||||
.driver = {
|
fpi_device_upektc_init (FpiDeviceUpektc *self)
|
||||||
.id = UPEKTC_ID,
|
{
|
||||||
.name = FP_COMPONENT,
|
}
|
||||||
.full_name = "UPEK TouchChip/Eikon Touch 300",
|
static void
|
||||||
.id_table = id_table,
|
fpi_device_upektc_class_init (FpiDeviceUpektcClass *klass)
|
||||||
.scan_type = FP_SCAN_TYPE_PRESS,
|
{
|
||||||
},
|
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
|
||||||
.flags = 0,
|
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
|
||||||
.img_height = IMAGE_HEIGHT,
|
|
||||||
.img_width = IMAGE_WIDTH,
|
|
||||||
|
|
||||||
.bz3_threshold = 30,
|
dev_class->id = "upektc";
|
||||||
.open = dev_init,
|
dev_class->full_name = "UPEK TouchChip/Eikon Touch 300";
|
||||||
.close = dev_deinit,
|
dev_class->type = FP_DEVICE_TYPE_USB;
|
||||||
.activate = dev_activate,
|
dev_class->id_table = id_table;
|
||||||
.deactivate = dev_deactivate,
|
dev_class->scan_type = FP_SCAN_TYPE_PRESS;
|
||||||
};
|
|
||||||
|
img_class->img_open = dev_init;
|
||||||
|
img_class->img_close = dev_deinit;
|
||||||
|
img_class->activate = dev_activate;
|
||||||
|
img_class->deactivate = dev_deactivate;
|
||||||
|
|
||||||
|
img_class->bz3_threshold = 30;
|
||||||
|
|
||||||
|
img_class->img_width = IMAGE_WIDTH;
|
||||||
|
img_class->img_height = IMAGE_HEIGHT;
|
||||||
|
}
|
||||||
|
|||||||
@@ -19,8 +19,7 @@
|
|||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __UPEKTC_H
|
#pragma once
|
||||||
#define __UPEKTC_H
|
|
||||||
|
|
||||||
#define UPEKTC_CMD_LEN 0x40
|
#define UPEKTC_CMD_LEN 0x40
|
||||||
#define IMAGE_WIDTH 208
|
#define IMAGE_WIDTH 208
|
||||||
@@ -29,7 +28,8 @@
|
|||||||
#define UPEKTC_SUM_THRESHOLD 10000
|
#define UPEKTC_SUM_THRESHOLD 10000
|
||||||
#define UPEKET_SUM_THRESHOLD 5000
|
#define UPEKET_SUM_THRESHOLD 5000
|
||||||
|
|
||||||
struct setup_cmd {
|
struct setup_cmd
|
||||||
|
{
|
||||||
unsigned char cmd[0x40];
|
unsigned char cmd[0x40];
|
||||||
int response_len;
|
int response_len;
|
||||||
};
|
};
|
||||||
@@ -1935,5 +1935,3 @@ static const unsigned char scan_cmd[0x40] = {
|
|||||||
0x05, 0x90, 0xf6, 0x77, 0x84, 0xf5, 0x2f, 0x01,
|
0x05, 0x90, 0xf6, 0x77, 0x84, 0xf5, 0x2f, 0x01,
|
||||||
0x05, 0x90, 0xf6, 0x00, 0xc8, 0x00, 0xec, 0x00
|
0x05, 0x90, 0xf6, 0x00, 0xc8, 0x00, 0xec, 0x00
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -17,8 +17,7 @@
|
|||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __UPEKTC_IMG_H
|
#pragma once
|
||||||
#define __UPEKTC_IMG_H
|
|
||||||
|
|
||||||
static const unsigned char upek2020_init_1[] = {
|
static const unsigned char upek2020_init_1[] = {
|
||||||
'C', 'i', 'a', 'o',
|
'C', 'i', 'a', 'o',
|
||||||
@@ -140,5 +139,3 @@ static const unsigned char upek2020_ack_frame[] = {
|
|||||||
0x30,
|
0x30,
|
||||||
0xac, 0x5b /* CRC */
|
0xac, 0x5b /* CRC */
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -28,10 +28,8 @@
|
|||||||
* powerdown? does windows do anything special on exit?
|
* powerdown? does windows do anything special on exit?
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define CTRL_IN 0xc0
|
|
||||||
#define CTRL_OUT 0x40
|
|
||||||
#define CTRL_TIMEOUT 1000
|
#define CTRL_TIMEOUT 1000
|
||||||
#define EP_IN (1 | LIBUSB_ENDPOINT_IN)
|
#define EP_IN (1 | FPI_USB_ENDPOINT_IN)
|
||||||
|
|
||||||
#define IMG_WIDTH 300
|
#define IMG_WIDTH 300
|
||||||
#define IMG_HEIGHT 288
|
#define IMG_HEIGHT 288
|
||||||
@@ -40,12 +38,18 @@
|
|||||||
#define RQ_SIZE (IMG_WIDTH * ROWS_PER_RQ)
|
#define RQ_SIZE (IMG_WIDTH * ROWS_PER_RQ)
|
||||||
#define IMG_SIZE (IMG_WIDTH * IMG_HEIGHT)
|
#define IMG_SIZE (IMG_WIDTH * IMG_HEIGHT)
|
||||||
|
|
||||||
struct v5s_dev {
|
struct _FpDeviceVcom5s
|
||||||
|
{
|
||||||
|
FpImageDevice parent;
|
||||||
|
|
||||||
int capture_iteration;
|
int capture_iteration;
|
||||||
struct fp_img *capture_img;
|
FpImage *capture_img;
|
||||||
gboolean loop_running;
|
gboolean loop_running;
|
||||||
gboolean deactivating;
|
gboolean deactivating;
|
||||||
};
|
};
|
||||||
|
G_DECLARE_FINAL_TYPE (FpDeviceVcom5s, fpi_device_vcom5s, FPI, DEVICE_VCOM5S,
|
||||||
|
FpImageDevice);
|
||||||
|
G_DEFINE_TYPE (FpDeviceVcom5s, fpi_device_vcom5s, FP_TYPE_IMAGE_DEVICE);
|
||||||
|
|
||||||
enum v5s_regs {
|
enum v5s_regs {
|
||||||
/* when using gain 0x29:
|
/* when using gain 0x29:
|
||||||
@@ -72,82 +76,42 @@ enum v5s_cmd {
|
|||||||
|
|
||||||
/***** REGISTER I/O *****/
|
/***** REGISTER I/O *****/
|
||||||
|
|
||||||
static void sm_write_reg_cb(struct libusb_transfer *transfer)
|
static void
|
||||||
{
|
sm_write_reg (FpiSsm *ssm,
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
FpDevice *dev,
|
||||||
|
unsigned char reg,
|
||||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
|
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
|
||||||
else
|
|
||||||
fpi_ssm_next_state(ssm);
|
|
||||||
|
|
||||||
g_free(transfer->buffer);
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sm_write_reg(struct fpi_ssm *ssm, unsigned char reg,
|
|
||||||
unsigned char value)
|
unsigned char value)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
|
||||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
|
||||||
unsigned char *data;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
if (!transfer) {
|
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fp_dbg ("set %02x=%02x", reg, value);
|
fp_dbg ("set %02x=%02x", reg, value);
|
||||||
data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE);
|
fpi_usb_transfer_fill_control (transfer,
|
||||||
libusb_fill_control_setup(data, CTRL_OUT, reg, value, 0, 0);
|
G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE,
|
||||||
libusb_fill_control_transfer(transfer, fpi_imgdev_get_usb_dev(dev), data, sm_write_reg_cb,
|
G_USB_DEVICE_REQUEST_TYPE_VENDOR,
|
||||||
ssm, CTRL_TIMEOUT);
|
G_USB_DEVICE_RECIPIENT_DEVICE,
|
||||||
r = libusb_submit_transfer(transfer);
|
reg, value, 0, 0);
|
||||||
if (r < 0) {
|
transfer->ssm = ssm;
|
||||||
g_free(data);
|
fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL,
|
||||||
libusb_free_transfer(transfer);
|
fpi_ssm_usb_transfer_cb, NULL);
|
||||||
fpi_ssm_mark_aborted(ssm, r);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sm_exec_cmd_cb(struct libusb_transfer *transfer)
|
static void
|
||||||
{
|
sm_exec_cmd (FpiSsm *ssm,
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
FpDevice *dev,
|
||||||
|
unsigned char cmd,
|
||||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
|
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
|
||||||
else
|
|
||||||
fpi_ssm_next_state(ssm);
|
|
||||||
|
|
||||||
g_free(transfer->buffer);
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void sm_exec_cmd(struct fpi_ssm *ssm, unsigned char cmd,
|
|
||||||
unsigned char param)
|
unsigned char param)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
|
||||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
|
||||||
unsigned char *data;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
if (!transfer) {
|
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fp_dbg ("cmd %02x param %02x", cmd, param);
|
fp_dbg ("cmd %02x param %02x", cmd, param);
|
||||||
data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE);
|
fpi_usb_transfer_fill_control (transfer,
|
||||||
libusb_fill_control_setup(data, CTRL_IN, cmd, param, 0, 0);
|
G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST,
|
||||||
libusb_fill_control_transfer(transfer, fpi_imgdev_get_usb_dev(dev), data, sm_exec_cmd_cb,
|
G_USB_DEVICE_REQUEST_TYPE_VENDOR,
|
||||||
ssm, CTRL_TIMEOUT);
|
G_USB_DEVICE_RECIPIENT_DEVICE,
|
||||||
r = libusb_submit_transfer(transfer);
|
cmd, param, 0, 0);
|
||||||
if (r < 0) {
|
transfer->ssm = ssm;
|
||||||
g_free(data);
|
fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL,
|
||||||
libusb_free_transfer(transfer);
|
fpi_ssm_usb_transfer_cb, NULL);
|
||||||
fpi_ssm_mark_aborted(ssm, r);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/***** FINGER DETECTION *****/
|
/***** FINGER DETECTION *****/
|
||||||
@@ -162,14 +126,16 @@ static void sm_exec_cmd(struct fpi_ssm *ssm, unsigned char cmd,
|
|||||||
#define DETBOX_COL_END (DETBOX_COL_START + DETBOX_COLS)
|
#define DETBOX_COL_END (DETBOX_COL_START + DETBOX_COLS)
|
||||||
#define FINGER_PRESENCE_THRESHOLD 100
|
#define FINGER_PRESENCE_THRESHOLD 100
|
||||||
|
|
||||||
static gboolean finger_is_present(unsigned char *data)
|
static gboolean
|
||||||
|
finger_is_present (unsigned char *data)
|
||||||
{
|
{
|
||||||
int row;
|
int row;
|
||||||
uint16_t imgavg = 0;
|
guint16 imgavg = 0;
|
||||||
|
|
||||||
for (row = DETBOX_ROW_START; row < DETBOX_ROW_END; row++) {
|
for (row = DETBOX_ROW_START; row < DETBOX_ROW_END; row++)
|
||||||
|
{
|
||||||
unsigned char *rowdata = data + (row * IMG_WIDTH);
|
unsigned char *rowdata = data + (row * IMG_WIDTH);
|
||||||
uint16_t rowavg = 0;
|
guint16 rowavg = 0;
|
||||||
int col;
|
int col;
|
||||||
|
|
||||||
for (col = DETBOX_COL_START; col < DETBOX_COL_END; col++)
|
for (col = DETBOX_COL_START; col < DETBOX_COL_END; col++)
|
||||||
@@ -180,78 +146,79 @@ static gboolean finger_is_present(unsigned char *data)
|
|||||||
imgavg /= DETBOX_ROWS;
|
imgavg /= DETBOX_ROWS;
|
||||||
fp_dbg ("img avg %d", imgavg);
|
fp_dbg ("img avg %d", imgavg);
|
||||||
|
|
||||||
return (imgavg <= FINGER_PRESENCE_THRESHOLD);
|
return imgavg <= FINGER_PRESENCE_THRESHOLD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/***** IMAGE ACQUISITION *****/
|
/***** IMAGE ACQUISITION *****/
|
||||||
|
|
||||||
static void capture_iterate(struct fpi_ssm *ssm);
|
static void capture_iterate (FpiSsm *ssm,
|
||||||
|
FpDevice *dev);
|
||||||
|
|
||||||
static void capture_cb(struct libusb_transfer *transfer)
|
static void
|
||||||
|
capture_cb (FpiUsbTransfer *transfer, FpDevice *device,
|
||||||
|
gpointer user_data, GError *error)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
FpImageDevice *imgdev = FP_IMAGE_DEVICE (device);
|
||||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S (device);
|
||||||
struct v5s_dev *vdev = fpi_imgdev_get_user_data(dev);
|
|
||||||
|
|
||||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
if (error)
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (++vdev->capture_iteration == NR_REQS) {
|
|
||||||
struct fp_img *img = vdev->capture_img;
|
|
||||||
/* must clear this early, otherwise the call chain takes us into
|
|
||||||
* loopsm_complete where we would free it, when in fact we are
|
|
||||||
* supposed to be handing off this image */
|
|
||||||
vdev->capture_img = NULL;
|
|
||||||
|
|
||||||
fpi_imgdev_report_finger_status(dev, finger_is_present(img->data));
|
|
||||||
fpi_imgdev_image_captured(dev, img);
|
|
||||||
fpi_ssm_next_state(ssm);
|
|
||||||
} else {
|
|
||||||
capture_iterate(ssm);
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void capture_iterate(struct fpi_ssm *ssm)
|
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
fpi_ssm_mark_failed (transfer->ssm, error);
|
||||||
struct v5s_dev *vdev = fpi_imgdev_get_user_data(dev);
|
|
||||||
int iteration = vdev->capture_iteration;
|
|
||||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
|
||||||
int r;
|
|
||||||
|
|
||||||
if (!transfer) {
|
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
libusb_fill_bulk_transfer(transfer, fpi_imgdev_get_usb_dev(dev), EP_IN,
|
if (++self->capture_iteration == NR_REQS)
|
||||||
vdev->capture_img->data + (RQ_SIZE * iteration), RQ_SIZE,
|
|
||||||
capture_cb, ssm, CTRL_TIMEOUT);
|
|
||||||
transfer->flags = LIBUSB_TRANSFER_SHORT_NOT_OK;
|
|
||||||
r = libusb_submit_transfer(transfer);
|
|
||||||
if (r < 0) {
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
fpi_ssm_mark_aborted(ssm, r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void sm_do_capture(struct fpi_ssm *ssm)
|
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
FpImage *img = self->capture_img;
|
||||||
struct v5s_dev *vdev = fpi_imgdev_get_user_data(dev);
|
/* must clear this early, otherwise the call chain takes us into
|
||||||
|
* loopsm_complete where we would free it, when in fact we are
|
||||||
|
* supposed to be handing off this image */
|
||||||
|
self->capture_img = NULL;
|
||||||
|
|
||||||
|
fpi_image_device_report_finger_status (imgdev,
|
||||||
|
finger_is_present (img->data));
|
||||||
|
fpi_image_device_image_captured (imgdev, img);
|
||||||
|
fpi_ssm_next_state (transfer->ssm);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
capture_iterate (transfer->ssm, device);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
capture_iterate (FpiSsm *ssm,
|
||||||
|
FpDevice *dev)
|
||||||
|
{
|
||||||
|
FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S (dev);
|
||||||
|
int iteration = self->capture_iteration;
|
||||||
|
FpiUsbTransfer *transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
|
||||||
|
|
||||||
|
transfer->ssm = ssm;
|
||||||
|
transfer->short_is_error = TRUE;
|
||||||
|
fpi_usb_transfer_fill_bulk_full (transfer,
|
||||||
|
EP_IN,
|
||||||
|
self->capture_img->data + (RQ_SIZE * iteration),
|
||||||
|
RQ_SIZE,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
fpi_usb_transfer_submit (transfer, CTRL_TIMEOUT, NULL, capture_cb, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
sm_do_capture (FpiSsm *ssm,
|
||||||
|
FpDevice *dev)
|
||||||
|
{
|
||||||
|
FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S (dev);
|
||||||
|
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (dev);
|
||||||
|
|
||||||
G_DEBUG_HERE ();
|
G_DEBUG_HERE ();
|
||||||
vdev->capture_img = fpi_img_new_for_imgdev(dev);
|
self->capture_img = fp_image_new (cls->img_width, cls->img_height);
|
||||||
vdev->capture_iteration = 0;
|
self->capture_iteration = 0;
|
||||||
capture_iterate(ssm);
|
capture_iterate (ssm, dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
/***** CAPTURE LOOP *****/
|
/***** CAPTURE LOOP *****/
|
||||||
@@ -265,121 +232,136 @@ enum loop_states {
|
|||||||
LOOP_NUM_STATES,
|
LOOP_NUM_STATES,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void loop_run_state(struct fpi_ssm *ssm)
|
static void
|
||||||
|
loop_run_state (FpiSsm *ssm, FpDevice *dev)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S (dev);
|
||||||
struct v5s_dev *vdev = fpi_imgdev_get_user_data(dev);
|
|
||||||
|
|
||||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
switch (fpi_ssm_get_cur_state (ssm))
|
||||||
|
{
|
||||||
case LOOP_SET_CONTRAST:
|
case LOOP_SET_CONTRAST:
|
||||||
sm_write_reg(ssm, REG_CONTRAST, 0x01);
|
sm_write_reg (ssm, dev, REG_CONTRAST, 0x01);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LOOP_SET_GAIN:
|
case LOOP_SET_GAIN:
|
||||||
sm_write_reg(ssm, REG_GAIN, 0x29);
|
sm_write_reg (ssm, dev, REG_GAIN, 0x29);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LOOP_CMD_SCAN:
|
case LOOP_CMD_SCAN:
|
||||||
if (vdev->deactivating) {
|
if (self->deactivating)
|
||||||
|
{
|
||||||
fp_dbg ("deactivating, marking completed");
|
fp_dbg ("deactivating, marking completed");
|
||||||
fpi_ssm_mark_completed (ssm);
|
fpi_ssm_mark_completed (ssm);
|
||||||
} else
|
}
|
||||||
sm_exec_cmd(ssm, CMD_SCAN, 0x00);
|
else
|
||||||
|
{
|
||||||
|
sm_exec_cmd (ssm, dev, CMD_SCAN, 0x00);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LOOP_CAPTURE:
|
case LOOP_CAPTURE:
|
||||||
sm_do_capture(ssm);
|
sm_do_capture (ssm, dev);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LOOP_CAPTURE_DONE:
|
case LOOP_CAPTURE_DONE:
|
||||||
fpi_ssm_jump_to_state (ssm, LOOP_CMD_SCAN);
|
fpi_ssm_jump_to_state (ssm, LOOP_CMD_SCAN);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
g_assert_not_reached ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void loopsm_complete(struct fpi_ssm *ssm)
|
static void
|
||||||
|
loopsm_complete (FpiSsm *ssm, FpDevice *dev, GError *error)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
FpImageDevice *imgdev = FP_IMAGE_DEVICE (dev);
|
||||||
struct v5s_dev *vdev = fpi_imgdev_get_user_data(dev);
|
FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S (dev);
|
||||||
int r = fpi_ssm_get_error(ssm);
|
|
||||||
|
|
||||||
fpi_ssm_free(ssm);
|
g_object_unref (self->capture_img);
|
||||||
fp_img_free(vdev->capture_img);
|
self->capture_img = NULL;
|
||||||
vdev->capture_img = NULL;
|
self->loop_running = FALSE;
|
||||||
vdev->loop_running = FALSE;
|
|
||||||
|
|
||||||
if (r)
|
if (error && !self->deactivating)
|
||||||
fpi_imgdev_session_error(dev, r);
|
fpi_image_device_session_error (imgdev, error);
|
||||||
|
else if (error)
|
||||||
|
g_error_free (error);
|
||||||
|
|
||||||
if (vdev->deactivating)
|
if (self->deactivating)
|
||||||
fpi_imgdev_deactivate_complete(dev);
|
fpi_image_device_deactivate_complete (imgdev, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
static void
|
||||||
|
dev_activate (FpImageDevice *dev)
|
||||||
{
|
{
|
||||||
struct v5s_dev *vdev = fpi_imgdev_get_user_data(dev);
|
FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S (dev);
|
||||||
struct fpi_ssm *ssm = fpi_ssm_new(fpi_imgdev_get_dev(dev), loop_run_state,
|
FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), loop_run_state, LOOP_NUM_STATES);
|
||||||
LOOP_NUM_STATES);
|
|
||||||
fpi_ssm_set_user_data(ssm, dev);
|
self->deactivating = FALSE;
|
||||||
vdev->deactivating = FALSE;
|
|
||||||
fpi_ssm_start (ssm, loopsm_complete);
|
fpi_ssm_start (ssm, loopsm_complete);
|
||||||
vdev->loop_running = TRUE;
|
self->loop_running = TRUE;
|
||||||
fpi_imgdev_activate_complete(dev, 0);
|
fpi_image_device_activate_complete (dev, NULL);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dev_deactivate(struct fp_img_dev *dev)
|
static void
|
||||||
|
dev_deactivate (FpImageDevice *dev)
|
||||||
{
|
{
|
||||||
struct v5s_dev *vdev = fpi_imgdev_get_user_data(dev);
|
FpDeviceVcom5s *self = FPI_DEVICE_VCOM5S (dev);
|
||||||
if (vdev->loop_running)
|
|
||||||
vdev->deactivating = TRUE;
|
if (self->loop_running)
|
||||||
|
self->deactivating = TRUE;
|
||||||
else
|
else
|
||||||
fpi_imgdev_deactivate_complete(dev);
|
fpi_image_device_deactivate_complete (dev, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
static void
|
||||||
|
dev_init (FpImageDevice *dev)
|
||||||
{
|
{
|
||||||
int r;
|
GError *error = NULL;
|
||||||
struct v5s_dev *v5s_dev;
|
|
||||||
|
|
||||||
v5s_dev = g_malloc0(sizeof(struct v5s_dev));
|
g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error);
|
||||||
fpi_imgdev_set_user_data(dev, v5s_dev);
|
|
||||||
|
|
||||||
r = libusb_claim_interface(fpi_imgdev_get_usb_dev(dev), 0);
|
fpi_image_device_open_complete (dev, error);
|
||||||
if (r < 0)
|
|
||||||
fp_err("could not claim interface 0: %s", libusb_error_name(r));
|
|
||||||
|
|
||||||
if (r == 0)
|
|
||||||
fpi_imgdev_open_complete(dev, 0);
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dev_deinit(struct fp_img_dev *dev)
|
static void
|
||||||
|
dev_deinit (FpImageDevice *dev)
|
||||||
{
|
{
|
||||||
struct v5s_dev *v5s_dev;
|
GError *error = NULL;
|
||||||
v5s_dev = fpi_imgdev_get_user_data(dev);
|
|
||||||
g_free(v5s_dev);
|
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)),
|
||||||
libusb_release_interface(fpi_imgdev_get_usb_dev(dev), 0);
|
0, 0, &error);
|
||||||
fpi_imgdev_close_complete(dev);
|
|
||||||
|
fpi_image_device_close_complete (dev, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct usb_id id_table[] = {
|
static const FpIdEntry id_table[] = {
|
||||||
{ .vendor = 0x061a, .product = 0x0110 },
|
{ .vid = 0x061a, .pid = 0x0110, },
|
||||||
{ 0, 0, 0, },
|
{ .vid = 0, .pid = 0, .driver_data = 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fp_img_driver vcom5s_driver = {
|
static void
|
||||||
.driver = {
|
fpi_device_vcom5s_init (FpDeviceVcom5s *self)
|
||||||
.id = VCOM5S_ID,
|
{
|
||||||
.name = FP_COMPONENT,
|
}
|
||||||
.full_name = "Veridicom 5thSense",
|
|
||||||
.id_table = id_table,
|
|
||||||
.scan_type = FP_SCAN_TYPE_PRESS,
|
|
||||||
},
|
|
||||||
.flags = 0,
|
|
||||||
.img_height = IMG_HEIGHT,
|
|
||||||
.img_width = IMG_WIDTH,
|
|
||||||
|
|
||||||
.open = dev_init,
|
static void
|
||||||
.close = dev_deinit,
|
fpi_device_vcom5s_class_init (FpDeviceVcom5sClass *klass)
|
||||||
.activate = dev_activate,
|
{
|
||||||
.deactivate = dev_deactivate,
|
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
|
||||||
};
|
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
|
||||||
|
|
||||||
|
dev_class->id = "vcom5s";
|
||||||
|
dev_class->full_name = "Veridicom 5thSense";
|
||||||
|
dev_class->type = FP_DEVICE_TYPE_USB;
|
||||||
|
dev_class->id_table = id_table;
|
||||||
|
dev_class->scan_type = FP_SCAN_TYPE_PRESS;
|
||||||
|
|
||||||
|
img_class->img_open = dev_init;
|
||||||
|
img_class->img_close = dev_deinit;
|
||||||
|
img_class->activate = dev_activate;
|
||||||
|
img_class->deactivate = dev_deactivate;
|
||||||
|
|
||||||
|
img_class->img_width = IMG_WIDTH;
|
||||||
|
img_class->img_height = IMG_HEIGHT;
|
||||||
|
}
|
||||||
|
|||||||
@@ -17,6 +17,10 @@
|
|||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "fpi-image-device.h"
|
||||||
|
|
||||||
/* Timeout for all send/recv operations, except interrupt waiting and abort */
|
/* Timeout for all send/recv operations, except interrupt waiting and abort */
|
||||||
#define VFS_USB_TIMEOUT 100
|
#define VFS_USB_TIMEOUT 100
|
||||||
/* Timeout for usb abort */
|
/* Timeout for usb abort */
|
||||||
@@ -47,7 +51,8 @@
|
|||||||
#define EP3_IN 0x83
|
#define EP3_IN 0x83
|
||||||
|
|
||||||
/* Fingerprint horizontal line */
|
/* Fingerprint horizontal line */
|
||||||
struct vfs_line {
|
struct vfs_line
|
||||||
|
{
|
||||||
/* It must be always 0x01 */
|
/* It must be always 0x01 */
|
||||||
unsigned char _0x01;
|
unsigned char _0x01;
|
||||||
/* It must be always 0xfe */
|
/* It must be always 0xfe */
|
||||||
@@ -74,7 +79,10 @@ struct vfs_line {
|
|||||||
} __attribute__((__packed__));
|
} __attribute__((__packed__));
|
||||||
|
|
||||||
/* The main driver structure */
|
/* The main driver structure */
|
||||||
struct vfs_dev_t {
|
struct _FpDeviceVfs0050
|
||||||
|
{
|
||||||
|
FpImageDevice parent;
|
||||||
|
|
||||||
/* One if we were asked to read fingerprint, zero otherwise */
|
/* One if we were asked to read fingerprint, zero otherwise */
|
||||||
char active;
|
char active;
|
||||||
|
|
||||||
@@ -84,15 +92,9 @@ struct vfs_dev_t {
|
|||||||
/* For dev_deactivate to check whether ssm still running or not */
|
/* For dev_deactivate to check whether ssm still running or not */
|
||||||
char ssm_active;
|
char ssm_active;
|
||||||
|
|
||||||
/* Current async transfer */
|
|
||||||
struct libusb_transfer *transfer;
|
|
||||||
|
|
||||||
/* Should we call fpi_imgdev_activate_complete or fpi_imgdev_deactivate_complete */
|
/* Should we call fpi_imgdev_activate_complete or fpi_imgdev_deactivate_complete */
|
||||||
char need_report;
|
char need_report;
|
||||||
|
|
||||||
/* Should we wait more for interrupt */
|
|
||||||
char wait_interrupt;
|
|
||||||
|
|
||||||
/* Received fingerprint raw lines */
|
/* Received fingerprint raw lines */
|
||||||
struct vfs_line *lines_buffer;
|
struct vfs_line *lines_buffer;
|
||||||
|
|
||||||
@@ -106,6 +108,8 @@ struct vfs_dev_t {
|
|||||||
unsigned char interrupt[8];
|
unsigned char interrupt[8];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
G_DECLARE_FINAL_TYPE (FpDeviceVfs0050, fpi_device_vfs0050, FPI, DEVICE_VFS0050, FpImageDevice)
|
||||||
|
|
||||||
/* SSM states for clear_ep2 */
|
/* SSM states for clear_ep2 */
|
||||||
enum SUBSM1 {
|
enum SUBSM1 {
|
||||||
SUBSM1_COMMAND_04,
|
SUBSM1_COMMAND_04,
|
||||||
|
|||||||
@@ -22,73 +22,52 @@
|
|||||||
#define FP_COMPONENT "vfs301"
|
#define FP_COMPONENT "vfs301"
|
||||||
|
|
||||||
#include "drivers_api.h"
|
#include "drivers_api.h"
|
||||||
#include "vfs301_proto.h"
|
#include "vfs301.h"
|
||||||
|
|
||||||
|
G_DEFINE_TYPE (FpDeviceVfs301, fpi_device_vfs301, FP_TYPE_IMAGE_DEVICE)
|
||||||
|
|
||||||
/************************** GENERIC STUFF *************************************/
|
/************************** GENERIC STUFF *************************************/
|
||||||
|
|
||||||
/* Callback of asynchronous sleep */
|
static int
|
||||||
static void async_sleep_cb(void *data)
|
submit_image (FpiSsm *ssm,
|
||||||
|
FpImageDevice *dev)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = data;
|
FpDeviceVfs301 *self = FPI_DEVICE_VFS301 (dev);
|
||||||
|
|
||||||
fpi_ssm_next_state(ssm);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Submit asynchronous sleep */
|
|
||||||
static void async_sleep(unsigned int msec, struct fpi_ssm *ssm)
|
|
||||||
{
|
|
||||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
|
||||||
struct fpi_timeout *timeout;
|
|
||||||
|
|
||||||
/* Add timeout */
|
|
||||||
timeout = fpi_timeout_add(msec, async_sleep_cb, ssm);
|
|
||||||
|
|
||||||
if (timeout == NULL) {
|
|
||||||
/* Failed to add timeout */
|
|
||||||
fp_err("failed to add timeout");
|
|
||||||
fpi_imgdev_session_error(dev, -ETIME);
|
|
||||||
fpi_ssm_mark_aborted(ssm, -ETIME);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int submit_image(struct fpi_ssm *ssm)
|
|
||||||
{
|
|
||||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
|
||||||
vfs301_dev_t *vdev = fpi_imgdev_get_user_data(dev);
|
|
||||||
int height;
|
int height;
|
||||||
struct fp_img *img;
|
FpImage *img;
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
/* XXX: This is probably handled by libfprint automagically? */
|
/* XXX: This is probably handled by libfprint automagically? */
|
||||||
if (vdev->scanline_count < 20) {
|
if (vdev->scanline_count < 20)
|
||||||
|
{
|
||||||
fpi_ssm_jump_to_state (ssm, M_REQUEST_PRINT);
|
fpi_ssm_jump_to_state (ssm, M_REQUEST_PRINT);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
img = fpi_img_new(VFS301_FP_OUTPUT_WIDTH * vdev->scanline_count);
|
img = fp_image_new (VFS301_FP_OUTPUT_WIDTH, self->scanline_count);
|
||||||
if (img == NULL)
|
if (img == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
vfs301_extract_image(vdev, img->data, &height);
|
vfs301_extract_image (self, img->data, &height);
|
||||||
|
|
||||||
/* TODO: how to detect flip? should the resulting image be
|
/* TODO: how to detect flip? should the resulting image be
|
||||||
* oriented so that it is equal e.g. to a fingerprint on a paper,
|
* oriented so that it is equal e.g. to a fingerprint on a paper,
|
||||||
* or to the finger when I look at it?) */
|
* or to the finger when I look at it?) */
|
||||||
img->flags = FP_IMG_COLORS_INVERTED | FP_IMG_V_FLIPPED;
|
img->flags = FPI_IMAGE_COLORS_INVERTED | FPI_IMAGE_V_FLIPPED;
|
||||||
|
|
||||||
|
/* The image buffer is larger at this point, but that does not
|
||||||
|
* matter. */
|
||||||
img->width = VFS301_FP_OUTPUT_WIDTH;
|
img->width = VFS301_FP_OUTPUT_WIDTH;
|
||||||
img->height = height;
|
img->height = height;
|
||||||
|
|
||||||
img = fpi_img_resize(img, img->height * img->width);
|
fpi_image_device_image_captured (dev, img);
|
||||||
fpi_imgdev_image_captured(dev, img);
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Loop ssm states */
|
/* Loop ssm states */
|
||||||
enum
|
enum {
|
||||||
{
|
|
||||||
/* Step 0 - Scan finger */
|
/* Step 0 - Scan finger */
|
||||||
M_REQUEST_PRINT,
|
M_REQUEST_PRINT,
|
||||||
M_WAIT_PRINT,
|
M_WAIT_PRINT,
|
||||||
@@ -103,43 +82,45 @@ enum
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* Exec loop sequential state machine */
|
/* Exec loop sequential state machine */
|
||||||
static void m_loop_state(struct fpi_ssm *ssm)
|
static void
|
||||||
|
m_loop_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
|
||||||
vfs301_dev_t *vdev = fpi_imgdev_get_user_data(dev);
|
FpDeviceVfs301 *self = FPI_DEVICE_VFS301 (_dev);
|
||||||
|
|
||||||
switch (fpi_ssm_get_cur_state(ssm)) {
|
switch (fpi_ssm_get_cur_state (ssm))
|
||||||
|
{
|
||||||
case M_REQUEST_PRINT:
|
case M_REQUEST_PRINT:
|
||||||
vfs301_proto_request_fingerprint(fpi_imgdev_get_usb_dev(dev), vdev);
|
vfs301_proto_request_fingerprint (self);
|
||||||
fpi_ssm_next_state (ssm);
|
fpi_ssm_next_state (ssm);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case M_WAIT_PRINT:
|
case M_WAIT_PRINT:
|
||||||
/* Wait fingerprint scanning */
|
/* Wait fingerprint scanning */
|
||||||
async_sleep(200, ssm);
|
fpi_ssm_next_state_delayed (ssm, 200, NULL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case M_CHECK_PRINT:
|
case M_CHECK_PRINT:
|
||||||
if (!vfs301_proto_peek_event(fpi_imgdev_get_usb_dev(dev), vdev))
|
if (!vfs301_proto_peek_event (self))
|
||||||
fpi_ssm_jump_to_state (ssm, M_WAIT_PRINT);
|
fpi_ssm_jump_to_state (ssm, M_WAIT_PRINT);
|
||||||
else
|
else
|
||||||
fpi_ssm_next_state (ssm);
|
fpi_ssm_next_state (ssm);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case M_READ_PRINT_START:
|
case M_READ_PRINT_START:
|
||||||
fpi_imgdev_report_finger_status(dev, TRUE);
|
fpi_image_device_report_finger_status (dev, TRUE);
|
||||||
vfs301_proto_process_event_start(fpi_imgdev_get_usb_dev(dev), vdev);
|
vfs301_proto_process_event_start (self);
|
||||||
fpi_ssm_next_state (ssm);
|
fpi_ssm_next_state (ssm);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case M_READ_PRINT_WAIT:
|
case M_READ_PRINT_WAIT:
|
||||||
/* Wait fingerprint scanning */
|
/* Wait fingerprint scanning */
|
||||||
async_sleep(200, ssm);
|
fpi_ssm_next_state_delayed (ssm, 200, NULL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case M_READ_PRINT_POLL:
|
case M_READ_PRINT_POLL:
|
||||||
{
|
{
|
||||||
int rv = vfs301_proto_process_event_poll(fpi_imgdev_get_usb_dev(dev), vdev);
|
int rv = vfs301_proto_process_event_poll (self);
|
||||||
g_assert (rv != VFS301_FAILURE);
|
g_assert (rv != VFS301_FAILURE);
|
||||||
if (rv == VFS301_ONGOING)
|
if (rv == VFS301_ONGOING)
|
||||||
fpi_ssm_jump_to_state (ssm, M_READ_PRINT_WAIT);
|
fpi_ssm_jump_to_state (ssm, M_READ_PRINT_WAIT);
|
||||||
@@ -149,148 +130,152 @@ static void m_loop_state(struct fpi_ssm *ssm)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case M_SUBMIT_PRINT:
|
case M_SUBMIT_PRINT:
|
||||||
if (submit_image(ssm)) {
|
if (submit_image (ssm, dev))
|
||||||
|
{
|
||||||
fpi_ssm_mark_completed (ssm);
|
fpi_ssm_mark_completed (ssm);
|
||||||
/* NOTE: finger off is expected only after submitting image... */
|
/* NOTE: finger off is expected only after submitting image... */
|
||||||
fpi_imgdev_report_finger_status(dev, FALSE);
|
fpi_image_device_report_finger_status (dev, FALSE);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
fpi_ssm_jump_to_state (ssm, M_REQUEST_PRINT);
|
fpi_ssm_jump_to_state (ssm, M_REQUEST_PRINT);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
g_assert_not_reached ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Complete loop sequential state machine */
|
/* Complete loop sequential state machine */
|
||||||
static void m_loop_complete(struct fpi_ssm *ssm)
|
static void
|
||||||
|
m_loop_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
|
||||||
{
|
{
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
g_warning ("State machine completed with an error: %s", error->message);
|
||||||
|
g_error_free (error);
|
||||||
|
}
|
||||||
/* Free sequential state machine */
|
/* Free sequential state machine */
|
||||||
fpi_ssm_free(ssm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Exec init sequential state machine */
|
/* Exec init sequential state machine */
|
||||||
static void m_init_state(struct fpi_ssm *ssm)
|
static void
|
||||||
|
m_init_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
FpDeviceVfs301 *self = FPI_DEVICE_VFS301 (_dev);
|
||||||
vfs301_dev_t *vdev = fpi_imgdev_get_user_data(dev);
|
|
||||||
|
|
||||||
g_assert (fpi_ssm_get_cur_state (ssm) == 0);
|
g_assert (fpi_ssm_get_cur_state (ssm) == 0);
|
||||||
|
|
||||||
vfs301_proto_init(fpi_imgdev_get_usb_dev(dev), vdev);
|
vfs301_proto_init (self);
|
||||||
|
|
||||||
fpi_ssm_mark_completed (ssm);
|
fpi_ssm_mark_completed (ssm);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Complete init sequential state machine */
|
/* Complete init sequential state machine */
|
||||||
static void m_init_complete(struct fpi_ssm *ssm)
|
static void
|
||||||
|
m_init_complete (FpiSsm *ssm, FpDevice *dev, GError *error)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
FpiSsm *ssm_loop;
|
||||||
struct fpi_ssm *ssm_loop;
|
|
||||||
|
|
||||||
if (!fpi_ssm_get_error(ssm)) {
|
fpi_image_device_activate_complete (FP_IMAGE_DEVICE (dev), error);
|
||||||
|
if (!error)
|
||||||
|
{
|
||||||
/* Notify activate complete */
|
/* Notify activate complete */
|
||||||
fpi_imgdev_activate_complete(dev, 0);
|
|
||||||
|
|
||||||
/* Start loop ssm */
|
/* Start loop ssm */
|
||||||
ssm_loop = fpi_ssm_new(fpi_imgdev_get_dev(dev), m_loop_state, M_LOOP_NUM_STATES);
|
ssm_loop = fpi_ssm_new (dev, m_loop_state, M_LOOP_NUM_STATES);
|
||||||
fpi_ssm_set_user_data(ssm_loop, dev);
|
|
||||||
fpi_ssm_start (ssm_loop, m_loop_complete);
|
fpi_ssm_start (ssm_loop, m_loop_complete);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Free sequential state machine */
|
/* Free sequential state machine */
|
||||||
fpi_ssm_free(ssm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Activate device */
|
/* Activate device */
|
||||||
static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
static void
|
||||||
|
dev_activate (FpImageDevice *dev)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm;
|
FpiSsm *ssm;
|
||||||
|
|
||||||
/* Start init ssm */
|
/* Start init ssm */
|
||||||
ssm = fpi_ssm_new(fpi_imgdev_get_dev(dev), m_init_state, 1);
|
ssm = fpi_ssm_new (FP_DEVICE (dev), m_init_state, 1);
|
||||||
fpi_ssm_set_user_data(ssm, dev);
|
|
||||||
fpi_ssm_start (ssm, m_init_complete);
|
fpi_ssm_start (ssm, m_init_complete);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Deactivate device */
|
/* Deactivate device */
|
||||||
static void dev_deactivate(struct fp_img_dev *dev)
|
static void
|
||||||
|
dev_deactivate (FpImageDevice *dev)
|
||||||
{
|
{
|
||||||
fpi_imgdev_deactivate_complete(dev);
|
FpDeviceVfs301 *self;
|
||||||
|
|
||||||
|
self = FPI_DEVICE_VFS301 (dev);
|
||||||
|
vfs301_proto_deinit (self);
|
||||||
|
fpi_image_device_deactivate_complete (dev, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dev_open(struct fp_img_dev *dev, unsigned long driver_data)
|
static void
|
||||||
|
dev_open (FpImageDevice *dev)
|
||||||
{
|
{
|
||||||
vfs301_dev_t *vdev = NULL;
|
FpDeviceVfs301 *self = FPI_DEVICE_VFS301 (dev);
|
||||||
int r;
|
GError *error = NULL;
|
||||||
|
|
||||||
/* Claim usb interface */
|
/* Claim usb interface */
|
||||||
r = libusb_claim_interface(fpi_imgdev_get_usb_dev(dev), 0);
|
g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error);
|
||||||
if (r < 0) {
|
|
||||||
/* Interface not claimed, return error */
|
|
||||||
fp_err("could not claim interface 0: %s", libusb_error_name(r));
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Initialize private structure */
|
/* Initialize private structure */
|
||||||
vdev = g_malloc0(sizeof(vfs301_dev_t));
|
self->scanline_count = 0;
|
||||||
fpi_imgdev_set_user_data(dev, vdev);
|
|
||||||
|
|
||||||
vdev->scanline_buf = malloc(0);
|
|
||||||
vdev->scanline_count = 0;
|
|
||||||
|
|
||||||
/* Notify open complete */
|
/* Notify open complete */
|
||||||
fpi_imgdev_open_complete(dev, 0);
|
fpi_image_device_open_complete (dev, error);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dev_close(struct fp_img_dev *dev)
|
static void
|
||||||
|
dev_close (FpImageDevice *dev)
|
||||||
{
|
{
|
||||||
vfs301_dev_t *vdev;
|
FpDeviceVfs301 *self = FPI_DEVICE_VFS301 (dev);
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
/* Release private structure */
|
/* Release private structure */
|
||||||
vdev = fpi_imgdev_get_user_data(dev);
|
g_clear_pointer (&self->scanline_buf, g_free);
|
||||||
free(vdev->scanline_buf);
|
|
||||||
g_free(vdev);
|
|
||||||
|
|
||||||
/* Release usb interface */
|
/* Release usb interface */
|
||||||
libusb_release_interface(fpi_imgdev_get_usb_dev(dev), 0);
|
g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)),
|
||||||
|
0, 0, &error);
|
||||||
|
|
||||||
/* Notify close complete */
|
/* Notify close complete */
|
||||||
fpi_imgdev_close_complete(dev);
|
fpi_image_device_close_complete (dev, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Usb id table of device */
|
/* Usb id table of device */
|
||||||
static const struct usb_id id_table[] =
|
static const FpIdEntry id_table[] = {
|
||||||
{
|
{ /* vfs301 */ .vid = 0x138a, .pid = 0x0005, },
|
||||||
{ .vendor = 0x138a, .product = 0x0005 /* vfs301 */ },
|
{ /* vfs300 */ .vid = 0x138a, .pid = 0x0008, },
|
||||||
{ .vendor = 0x138a, .product = 0x0008 /* vfs300 */ },
|
{ .vid = 0, .pid = 0, .driver_data = 0 },
|
||||||
{ 0, 0, 0, },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Device driver definition */
|
static void
|
||||||
struct fp_img_driver vfs301_driver =
|
fpi_device_vfs301_init (FpDeviceVfs301 *self)
|
||||||
{
|
{
|
||||||
/* Driver specification */
|
}
|
||||||
.driver =
|
static void
|
||||||
|
fpi_device_vfs301_class_init (FpDeviceVfs301Class *klass)
|
||||||
{
|
{
|
||||||
.id = VFS301_ID,
|
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
|
||||||
.name = FP_COMPONENT,
|
FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
|
||||||
.full_name = "Validity VFS301",
|
|
||||||
.id_table = id_table,
|
|
||||||
.scan_type = FP_SCAN_TYPE_SWIPE,
|
|
||||||
},
|
|
||||||
|
|
||||||
/* Image specification */
|
dev_class->id = "vfs301";
|
||||||
.flags = 0,
|
dev_class->full_name = "Validity VFS301";
|
||||||
.img_width = VFS301_FP_WIDTH,
|
dev_class->type = FP_DEVICE_TYPE_USB;
|
||||||
.img_height = -1,
|
dev_class->id_table = id_table;
|
||||||
.bz3_threshold = 24,
|
dev_class->scan_type = FP_SCAN_TYPE_SWIPE;
|
||||||
|
|
||||||
/* Routine specification */
|
img_class->img_open = dev_open;
|
||||||
.open = dev_open,
|
img_class->img_close = dev_close;
|
||||||
.close = dev_close,
|
img_class->activate = dev_activate;
|
||||||
.activate = dev_activate,
|
img_class->deactivate = dev_deactivate;
|
||||||
.deactivate = dev_deactivate,
|
|
||||||
};
|
img_class->bz3_threshold = 24;
|
||||||
|
|
||||||
|
img_class->img_width = VFS301_FP_WIDTH;
|
||||||
|
img_class->img_height = -1;
|
||||||
|
}
|
||||||
|
|||||||
142
libfprint/drivers/vfs301.h
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
/*
|
||||||
|
* vfs301/vfs300 fingerprint reader driver
|
||||||
|
* https://github.com/andree182/vfs301
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011-2012 Andrej Krutak <dev@andree.sk>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "fpi-usb-transfer.h"
|
||||||
|
#include "fpi-image-device.h"
|
||||||
|
|
||||||
|
enum {
|
||||||
|
VFS301_DEFAULT_WAIT_TIMEOUT = 300,
|
||||||
|
|
||||||
|
VFS301_SEND_ENDPOINT = 0x01,
|
||||||
|
VFS301_RECEIVE_ENDPOINT_CTRL = 0x81,
|
||||||
|
VFS301_RECEIVE_ENDPOINT_DATA = 0x82
|
||||||
|
};
|
||||||
|
|
||||||
|
#define VFS301_FP_RECV_LEN_1 (84032)
|
||||||
|
#define VFS301_FP_RECV_LEN_2 (84096)
|
||||||
|
|
||||||
|
struct _FpDeviceVfs301
|
||||||
|
{
|
||||||
|
FpImageDevice parent;
|
||||||
|
|
||||||
|
/* buffer to hold raw scanlines */
|
||||||
|
unsigned char *scanline_buf;
|
||||||
|
int scanline_count;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
VFS301_ONGOING = 0,
|
||||||
|
VFS301_ENDED = 1,
|
||||||
|
VFS301_FAILURE = -1
|
||||||
|
} recv_progress;
|
||||||
|
int recv_exp_amt;
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DECLARE_FINAL_TYPE (FpDeviceVfs301, fpi_device_vfs301, FPI, DEVICE_VFS301, FpImageDevice)
|
||||||
|
|
||||||
|
enum {
|
||||||
|
/* Width of the scanned data in px */
|
||||||
|
VFS301_FP_WIDTH = 200,
|
||||||
|
|
||||||
|
/* sizeof(fp_line_t) */
|
||||||
|
VFS301_FP_FRAME_SIZE = 288,
|
||||||
|
/* Width of output line */
|
||||||
|
#ifndef OUTPUT_RAW
|
||||||
|
VFS301_FP_OUTPUT_WIDTH = VFS301_FP_WIDTH,
|
||||||
|
#else
|
||||||
|
VFS301_FP_OUTPUT_WIDTH = VFS301_FP_FRAME_SIZE,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
VFS301_FP_SUM_LINES = 3,
|
||||||
|
|
||||||
|
#ifdef SCAN_FINISH_DETECTION
|
||||||
|
/* TODO: The following changes (seen ~60 and ~80) In that
|
||||||
|
* case we'll need to calibrate this from empty data somehow... */
|
||||||
|
VFS301_FP_SUM_MEDIAN = 60,
|
||||||
|
VFS301_FP_SUM_EMPTY_RANGE = 5,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Minimum average difference between returned lines */
|
||||||
|
VFS301_FP_LINE_DIFF_THRESHOLD = 15,
|
||||||
|
|
||||||
|
/* Maximum waiting time for a single fingerprint frame */
|
||||||
|
VFS301_FP_RECV_TIMEOUT = 2000
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Arrays of this structure is returned during the initialization as a response
|
||||||
|
* to the 0x02D0 messages.
|
||||||
|
* It seems to be always the same - what is it for? Some kind of confirmation?
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
unsigned char sync_0x01;
|
||||||
|
unsigned char sync_0xfe;
|
||||||
|
|
||||||
|
unsigned char counter_lo;
|
||||||
|
unsigned char counter_hi; /* FIXME ? */
|
||||||
|
|
||||||
|
unsigned char flags[3];
|
||||||
|
|
||||||
|
unsigned char sync_0x00;
|
||||||
|
|
||||||
|
unsigned char scan[VFS301_FP_WIDTH];
|
||||||
|
} vfs301_init_line_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
unsigned char sync_0x01;
|
||||||
|
unsigned char sync_0xfe;
|
||||||
|
|
||||||
|
unsigned char counter_lo;
|
||||||
|
unsigned char counter_hi;
|
||||||
|
|
||||||
|
unsigned char sync_0x08[2]; /* XXX: always? 0x08 0x08 */
|
||||||
|
/* 0x08 | 0x18 - Looks like 0x08 marks good quality lines */
|
||||||
|
unsigned char flag_1;
|
||||||
|
unsigned char sync_0x00;
|
||||||
|
|
||||||
|
unsigned char scan[VFS301_FP_WIDTH];
|
||||||
|
|
||||||
|
/* A offsetted, stretched, inverted copy of scan... probably could
|
||||||
|
* serve finger motion speed detection?
|
||||||
|
* Seems to be subdivided to some 10B + 53B + 1B blocks */
|
||||||
|
unsigned char mirror[64];
|
||||||
|
|
||||||
|
/* Some kind of sum of the scan, very low contrast */
|
||||||
|
unsigned char sum1[2];
|
||||||
|
unsigned char sum2[11];
|
||||||
|
unsigned char sum3[3];
|
||||||
|
} vfs301_line_t;
|
||||||
|
|
||||||
|
void vfs301_proto_init (FpDeviceVfs301 *dev);
|
||||||
|
void vfs301_proto_deinit (FpDeviceVfs301 *dev);
|
||||||
|
|
||||||
|
void vfs301_proto_request_fingerprint (FpDeviceVfs301 *dev);
|
||||||
|
|
||||||
|
/** returns 0 if no event is ready, or 1 if there is one... */
|
||||||
|
int vfs301_proto_peek_event (FpDeviceVfs301 *dev);
|
||||||
|
void vfs301_proto_process_event_start (FpDeviceVfs301 *dev);
|
||||||
|
int vfs301_proto_process_event_poll (FpDeviceVfs301 *dev);
|
||||||
|
|
||||||
|
void vfs301_extract_image (FpDeviceVfs301 *vfs,
|
||||||
|
unsigned char *output,
|
||||||
|
int *output_height);
|
||||||
@@ -33,22 +33,24 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include <libusb-1.0/libusb.h>
|
|
||||||
|
|
||||||
#include "vfs301_proto.h"
|
#include "fpi-usb-transfer.h"
|
||||||
|
#include "vfs301.h"
|
||||||
#include "vfs301_proto_fragments.h"
|
#include "vfs301_proto_fragments.h"
|
||||||
|
|
||||||
/************************** USB STUFF *****************************************/
|
/************************** USB STUFF *****************************************/
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
static void usb_print_packet(int dir, int rv, const unsigned char *data, int length)
|
static void
|
||||||
|
usb_print_packet (int dir, GError *error, const guint8 *data, int length)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%s, rv %d, len %d\n", dir ? "send" : "recv", rv, length);
|
fprintf (stderr, "%s, error %s, len %d\n", dir ? "send" : "recv", error ? error->message : "-", length);
|
||||||
|
|
||||||
#ifdef PRINT_VERBOSE
|
#ifdef PRINT_VERBOSE
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < MIN(length, 128); i++) {
|
for (i = 0; i < MIN (length, 128); i++)
|
||||||
|
{
|
||||||
fprintf (stderr, "%.2X ", data[i]);
|
fprintf (stderr, "%.2X ", data[i]);
|
||||||
if (i % 8 == 7)
|
if (i % 8 == 7)
|
||||||
fprintf (stderr, " ");
|
fprintf (stderr, " ");
|
||||||
@@ -61,106 +63,136 @@ static void usb_print_packet(int dir, int rv, const unsigned char *data, int len
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int usb_recv(
|
static void
|
||||||
vfs301_dev_t *dev,
|
usb_recv (FpDeviceVfs301 *dev, guint8 endpoint, int max_bytes, FpiUsbTransfer **out, GError **error)
|
||||||
struct libusb_device_handle *devh, unsigned char endpoint, int max_bytes)
|
|
||||||
{
|
{
|
||||||
g_assert(max_bytes <= sizeof(dev->recv_buf));
|
GError *err = NULL;
|
||||||
|
|
||||||
int r = libusb_bulk_transfer(
|
g_autoptr(FpiUsbTransfer) transfer = NULL;
|
||||||
devh, endpoint,
|
|
||||||
dev->recv_buf, max_bytes,
|
/* XXX: This function swallows any transfer errors, that is obviously
|
||||||
&dev->recv_len, VFS301_DEFAULT_WAIT_TIMEOUT
|
* quite bad (it used to assert on no-error)! */
|
||||||
);
|
|
||||||
|
transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
|
||||||
|
transfer->short_is_error = TRUE;
|
||||||
|
fpi_usb_transfer_fill_bulk (transfer, endpoint, max_bytes);
|
||||||
|
|
||||||
|
fpi_usb_transfer_submit_sync (transfer, VFS301_DEFAULT_WAIT_TIMEOUT, &err);
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
usb_print_packet(0, r, dev->recv_buf, dev->recv_len);
|
usb_print_packet (0, err, transfer->buffer, transfer->actual_length);
|
||||||
#endif
|
#endif
|
||||||
|
if (err)
|
||||||
if (r < 0)
|
{
|
||||||
return r;
|
if (!error)
|
||||||
return 0;
|
g_warning ("Unhandled receive error: %s", err->message);
|
||||||
|
g_propagate_error (error, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int usb_send(
|
if (out)
|
||||||
struct libusb_device_handle *devh, const unsigned char *data, int length)
|
*out = g_steal_pointer (&transfer);
|
||||||
{
|
}
|
||||||
int transferred = 0;
|
|
||||||
|
|
||||||
int r = libusb_bulk_transfer(
|
static void
|
||||||
devh, VFS301_SEND_ENDPOINT,
|
usb_send (FpDeviceVfs301 *dev, const guint8 *data, gssize length, GError **error)
|
||||||
(unsigned char *)data, length, &transferred, VFS301_DEFAULT_WAIT_TIMEOUT
|
{
|
||||||
);
|
GError *err = NULL;
|
||||||
|
|
||||||
|
g_autoptr(FpiUsbTransfer) transfer = NULL;
|
||||||
|
|
||||||
|
/* XXX: This function swallows any transfer errors, that is obviously
|
||||||
|
* quite bad (it used to assert on no-error)! */
|
||||||
|
|
||||||
|
transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
|
||||||
|
transfer->short_is_error = TRUE;
|
||||||
|
fpi_usb_transfer_fill_bulk_full (transfer, VFS301_SEND_ENDPOINT, (guint8 *) data, length, g_free);
|
||||||
|
|
||||||
|
fpi_usb_transfer_submit_sync (transfer, VFS301_DEFAULT_WAIT_TIMEOUT, &err);
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
usb_print_packet(1, r, data, length);
|
usb_print_packet (1, err, data, length);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
g_assert(r == 0);
|
if (err)
|
||||||
|
{
|
||||||
if (r < 0)
|
g_warning ("Error while sending data, continuing anyway: %s", err->message);
|
||||||
return r;
|
g_propagate_error (error, err);
|
||||||
if (transferred < length)
|
}
|
||||||
return r;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************** OUT MESSAGES GENERATION ***************************/
|
/************************** OUT MESSAGES GENERATION ***************************/
|
||||||
|
|
||||||
static void vfs301_proto_generate_0B(int subtype, unsigned char *data, int *len)
|
static guint8 *
|
||||||
|
vfs301_proto_generate_0B (int subtype, gssize *len)
|
||||||
{
|
{
|
||||||
|
guint8 *res = g_malloc0 (39);
|
||||||
|
guint8 *data = res;
|
||||||
|
|
||||||
*data = 0x0B;
|
*data = 0x0B;
|
||||||
*len = 1;
|
*len = 1;
|
||||||
data++;
|
data++;
|
||||||
|
|
||||||
memset(data, 0, 39);
|
|
||||||
*len += 38;
|
*len += 38;
|
||||||
|
|
||||||
data[20] = subtype;
|
data[20] = subtype;
|
||||||
|
|
||||||
switch (subtype) {
|
switch (subtype)
|
||||||
|
{
|
||||||
case 0x04:
|
case 0x04:
|
||||||
data[34] = 0x9F;
|
data[34] = 0x9F;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x05:
|
case 0x05:
|
||||||
data[34] = 0xAB;
|
data[34] = 0xAB;
|
||||||
len++;
|
/* NOTE: There was a len++ here, which could never do anything */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
g_assert_not_reached ();
|
g_assert_not_reached ();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define HEX_TO_INT(c) \
|
#define HEX_TO_INT(c) \
|
||||||
(((c) >= '0' && (c) <= '9') ? ((c) - '0') : ((c) - 'A' + 10))
|
(((c) >= '0' && (c) <= '9') ? ((c) - '0') : ((c) - 'A' + 10))
|
||||||
|
|
||||||
static void translate_str(const char **srcL, unsigned char *data, int *len)
|
static guint8 *
|
||||||
|
translate_str (const char **srcL, gssize *len)
|
||||||
{
|
{
|
||||||
|
guint8 *res = NULL;
|
||||||
|
guint8 *dst;
|
||||||
|
const char **src_pos;
|
||||||
const char *src;
|
const char *src;
|
||||||
unsigned char *dataOrig = data;
|
gssize src_len = 0;
|
||||||
|
|
||||||
while (*srcL != NULL) {
|
for (src_pos = srcL; *src_pos; src_pos++)
|
||||||
src = *srcL;
|
{
|
||||||
while (*src != '\0') {
|
gint tmp;
|
||||||
g_assert(*src != '\0');
|
|
||||||
g_assert(*(src +1) != '\0');
|
src = *src_pos;
|
||||||
*data = (unsigned char)((HEX_TO_INT(*src) << 4) | (HEX_TO_INT(*(src + 1))));
|
tmp = strlen (src);
|
||||||
|
g_assert (tmp % 2 == 0);
|
||||||
data++;
|
src_len += tmp;
|
||||||
src += 2;
|
}
|
||||||
}
|
|
||||||
|
*len = src_len / 2;
|
||||||
srcL++;
|
res = g_malloc0 (*len);
|
||||||
}
|
dst = res;
|
||||||
|
|
||||||
*len = data - dataOrig;
|
for (src_pos = srcL; *src_pos; src_pos++)
|
||||||
}
|
for (src = *src_pos; *src; src += 2, dst += 1)
|
||||||
|
*dst = (guint8) ((HEX_TO_INT (src[0]) << 4) | (HEX_TO_INT (src[1])));
|
||||||
static void vfs301_proto_generate(int type, int subtype, unsigned char *data, int *len)
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static guint8 *
|
||||||
|
vfs301_proto_generate (int type, int subtype, gssize *len)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
{
|
{
|
||||||
switch (type) {
|
|
||||||
case 0x01:
|
case 0x01:
|
||||||
case 0x04:
|
case 0x04:
|
||||||
/* After cmd 0x04 is sent, a data is received on VALIDITY_RECEIVE_ENDPOINT_CTRL.
|
/* After cmd 0x04 is sent, a data is received on VALIDITY_RECEIVE_ENDPOINT_CTRL.
|
||||||
@@ -173,12 +205,18 @@ static void vfs301_proto_generate(int type, int subtype, unsigned char *data, in
|
|||||||
case 0x17:
|
case 0x17:
|
||||||
case 0x19:
|
case 0x19:
|
||||||
case 0x1A:
|
case 0x1A:
|
||||||
|
{
|
||||||
|
guint8 *data = g_malloc0 (1);
|
||||||
*data = type;
|
*data = type;
|
||||||
*len = 1;
|
*len = 1;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x0B:
|
case 0x0B:
|
||||||
vfs301_proto_generate_0B(subtype, data, len);
|
return vfs301_proto_generate_0B (subtype, len);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x02D0:
|
case 0x02D0:
|
||||||
{
|
{
|
||||||
const char **dataLs[] = {
|
const char **dataLs[] = {
|
||||||
@@ -190,76 +228,93 @@ static void vfs301_proto_generate(int type, int subtype, unsigned char *data, in
|
|||||||
vfs301_02D0_06,
|
vfs301_02D0_06,
|
||||||
vfs301_02D0_07,
|
vfs301_02D0_07,
|
||||||
};
|
};
|
||||||
g_assert((int)subtype <= (int)(sizeof(dataLs) / sizeof(dataLs[0])));
|
g_assert ((int) subtype <= G_N_ELEMENTS (dataLs));
|
||||||
translate_str(dataLs[subtype - 1], data, len);
|
return translate_str (dataLs[subtype - 1], len);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x0220:
|
case 0x0220:
|
||||||
switch (subtype) {
|
switch (subtype)
|
||||||
|
{
|
||||||
case 1:
|
case 1:
|
||||||
translate_str(vfs301_0220_01, data, len);
|
return translate_str (vfs301_0220_01, len);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
translate_str(vfs301_0220_02, data, len);
|
return translate_str (vfs301_0220_02, len);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
translate_str(vfs301_0220_03, data, len);
|
return translate_str (vfs301_0220_03, len);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xFA00:
|
case 0xFA00:
|
||||||
case 0x2C01:
|
case 0x2C01:
|
||||||
case 0x5E01:
|
case 0x5E01: {
|
||||||
translate_str(vfs301_next_scan_template, data, len);
|
guint8 *data;
|
||||||
unsigned char *field = data + *len - (sizeof(S4_TAIL) - 1) / 2 - 4;
|
guint8 *field;
|
||||||
|
|
||||||
g_assert(*field == 0xDE);
|
data = translate_str (vfs301_next_scan_template, len);
|
||||||
g_assert(*(field + 1) == 0xAD);
|
field = data + *len - (sizeof (S4_TAIL) - 1) / 2 - 4;
|
||||||
g_assert(*(field + 2) == 0xDE);
|
|
||||||
g_assert(*(field + 3) == 0xAD);
|
|
||||||
|
|
||||||
*field = (unsigned char)((subtype >> 8) & 0xFF);
|
g_assert (field >= data && field < data + *len);
|
||||||
*(field + 1) = (unsigned char)(subtype & 0xFF);
|
g_assert (field[0] == 0xDE);
|
||||||
*(field + 2) = *field;
|
g_assert (field[1] == 0xAD);
|
||||||
*(field + 3) = *(field + 1);
|
g_assert (field[2] == 0xDE);
|
||||||
|
g_assert (field[3] == 0xAD);
|
||||||
|
|
||||||
|
field[0] = (guint8) ((subtype >> 8) & 0xFF);
|
||||||
|
field[1] = (guint8) (subtype & 0xFF);
|
||||||
|
field[2] = field[0];
|
||||||
|
field[3] = field[1];
|
||||||
|
|
||||||
|
return data;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
g_assert(0);
|
g_assert_not_reached ();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x06:
|
case 0x06:
|
||||||
g_assert_not_reached();
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
g_assert_not_reached();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_assert_not_reached ();
|
||||||
|
*len = 0;
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************** SCAN IMAGE PROCESSING *****************************/
|
/************************** SCAN IMAGE PROCESSING *****************************/
|
||||||
|
|
||||||
#ifdef SCAN_FINISH_DETECTION
|
#ifdef SCAN_FINISH_DETECTION
|
||||||
static int img_is_finished_scan(fp_line_t *lines, int no_lines)
|
static int
|
||||||
|
img_is_finished_scan (fp_line_t *lines, int no_lines)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int j;
|
int j;
|
||||||
int rv = 1;
|
int rv = 1;
|
||||||
|
|
||||||
for (i = no_lines - VFS301_FP_SUM_LINES; i < no_lines; i++) {
|
for (i = no_lines - VFS301_FP_SUM_LINES; i < no_lines; i++)
|
||||||
|
{
|
||||||
/* check the line for fingerprint data */
|
/* check the line for fingerprint data */
|
||||||
for (j = 0; j < sizeof(lines[i].sum2); j++) {
|
for (j = 0; j < sizeof (lines[i].sum2); j++)
|
||||||
if (lines[i].sum2[j] > (VFS301_FP_SUM_MEDIAN + VFS301_FP_SUM_EMPTY_RANGE))
|
if (lines[i].sum2[j] > (VFS301_FP_SUM_MEDIAN + VFS301_FP_SUM_EMPTY_RANGE))
|
||||||
rv = 0;
|
rv = 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int scanline_diff(const unsigned char *scanlines, int prev, int cur)
|
static int
|
||||||
|
scanline_diff (const guint8 *scanlines, int prev, int cur)
|
||||||
{
|
{
|
||||||
const unsigned char *line1 = scanlines + prev * VFS301_FP_OUTPUT_WIDTH;
|
const guint8 *line1 = scanlines + prev * VFS301_FP_OUTPUT_WIDTH;
|
||||||
const unsigned char *line2 = scanlines + cur * VFS301_FP_OUTPUT_WIDTH;
|
const guint8 *line2 = scanlines + cur * VFS301_FP_OUTPUT_WIDTH;
|
||||||
int i;
|
int i;
|
||||||
int diff;
|
int diff;
|
||||||
|
|
||||||
@@ -271,7 +326,8 @@ static int scanline_diff(const unsigned char *scanlines, int prev, int cur)
|
|||||||
|
|
||||||
/* TODO: This doesn't work too well when there are parallel lines in the
|
/* TODO: This doesn't work too well when there are parallel lines in the
|
||||||
* fingerprint. */
|
* fingerprint. */
|
||||||
for (diff = 0, i = 0; i < VFS301_FP_WIDTH; i++) {
|
for (diff = 0, i = 0; i < VFS301_FP_WIDTH; i++)
|
||||||
|
{
|
||||||
if (*line1 > *line2)
|
if (*line1 > *line2)
|
||||||
diff += *line1 - *line2;
|
diff += *line1 - *line2;
|
||||||
else
|
else
|
||||||
@@ -281,15 +337,15 @@ static int scanline_diff(const unsigned char *scanlines, int prev, int cur)
|
|||||||
line2++;
|
line2++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ((diff / VFS301_FP_WIDTH) > VFS301_FP_LINE_DIFF_THRESHOLD);
|
return (diff / VFS301_FP_WIDTH) > VFS301_FP_LINE_DIFF_THRESHOLD;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Transform the input data to a normalized fingerprint scan */
|
/** Transform the input data to a normalized fingerprint scan */
|
||||||
void vfs301_extract_image(
|
void
|
||||||
vfs301_dev_t *vfs, unsigned char *output, int *output_height
|
vfs301_extract_image (FpDeviceVfs301 *vfs, guint8 *output, int *output_height
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
const unsigned char *scanlines = vfs->scanline_buf;
|
const guint8 *scanlines = vfs->scanline_buf;
|
||||||
int last_line;
|
int last_line;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@@ -305,8 +361,10 @@ void vfs301_extract_image(
|
|||||||
* of bi/tri-linear resampling to get the output (so that we don't get so
|
* of bi/tri-linear resampling to get the output (so that we don't get so
|
||||||
* many false edges etc.).
|
* many false edges etc.).
|
||||||
*/
|
*/
|
||||||
for (i = 1; i < vfs->scanline_count; i++) {
|
for (i = 1; i < vfs->scanline_count; i++)
|
||||||
if (scanline_diff(scanlines, last_line, i)) {
|
{
|
||||||
|
if (scanline_diff (scanlines, last_line, i))
|
||||||
|
{
|
||||||
memcpy (
|
memcpy (
|
||||||
output + VFS301_FP_OUTPUT_WIDTH * (*output_height),
|
output + VFS301_FP_OUTPUT_WIDTH * (*output_height),
|
||||||
scanlines + VFS301_FP_OUTPUT_WIDTH * i,
|
scanlines + VFS301_FP_OUTPUT_WIDTH * i,
|
||||||
@@ -318,35 +376,38 @@ void vfs301_extract_image(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int img_process_data(
|
static int
|
||||||
int first_block, vfs301_dev_t *dev, const unsigned char *buf, int len
|
img_process_data (int first_block, FpDeviceVfs301 *dev, const guint8 *buf, int len)
|
||||||
)
|
|
||||||
{
|
{
|
||||||
vfs301_line_t *lines = (vfs301_line_t *) buf;
|
vfs301_line_t *lines = (vfs301_line_t *) buf;
|
||||||
int no_lines = len / sizeof (vfs301_line_t);
|
int no_lines = len / sizeof (vfs301_line_t);
|
||||||
int i;
|
int i;
|
||||||
/*int no_nonempty;*/
|
/*int no_nonempty;*/
|
||||||
unsigned char *cur_line;
|
guint8 *cur_line;
|
||||||
int last_img_height;
|
int last_img_height;
|
||||||
|
|
||||||
#ifdef SCAN_FINISH_DETECTION
|
#ifdef SCAN_FINISH_DETECTION
|
||||||
int finished_scan;
|
int finished_scan;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (first_block) {
|
if (first_block)
|
||||||
|
{
|
||||||
last_img_height = 0;
|
last_img_height = 0;
|
||||||
dev->scanline_count = no_lines;
|
dev->scanline_count = no_lines;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
last_img_height = dev->scanline_count;
|
last_img_height = dev->scanline_count;
|
||||||
dev->scanline_count += no_lines;
|
dev->scanline_count += no_lines;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev->scanline_buf = realloc(dev->scanline_buf, dev->scanline_count * VFS301_FP_OUTPUT_WIDTH);
|
dev->scanline_buf = g_realloc (dev->scanline_buf, dev->scanline_count * VFS301_FP_OUTPUT_WIDTH);
|
||||||
g_assert(dev->scanline_buf != NULL);
|
|
||||||
|
|
||||||
for (cur_line = dev->scanline_buf + last_img_height * VFS301_FP_OUTPUT_WIDTH, i = 0;
|
for (cur_line = dev->scanline_buf + last_img_height * VFS301_FP_OUTPUT_WIDTH, i = 0;
|
||||||
i < no_lines;
|
i < no_lines;
|
||||||
i++, cur_line += VFS301_FP_OUTPUT_WIDTH
|
i++, cur_line += VFS301_FP_OUTPUT_WIDTH
|
||||||
) {
|
)
|
||||||
|
{
|
||||||
#ifndef OUTPUT_RAW
|
#ifndef OUTPUT_RAW
|
||||||
memcpy (cur_line, lines[i].scan, VFS301_FP_OUTPUT_WIDTH);
|
memcpy (cur_line, lines[i].scan, VFS301_FP_OUTPUT_WIDTH);
|
||||||
#else
|
#else
|
||||||
@@ -365,115 +426,127 @@ static int img_process_data(
|
|||||||
|
|
||||||
/************************** PROTOCOL STUFF ************************************/
|
/************************** PROTOCOL STUFF ************************************/
|
||||||
|
|
||||||
static unsigned char usb_send_buf[0x2000];
|
|
||||||
|
|
||||||
#define USB_RECV(from, len) \
|
#define USB_RECV(from, len) \
|
||||||
usb_recv(dev, devh, from, len)
|
usb_recv (dev, from, len, NULL, NULL)
|
||||||
|
|
||||||
#define USB_SEND(type, subtype) \
|
#define USB_SEND(type, subtype) \
|
||||||
{ \
|
{ \
|
||||||
int len; \
|
const guint8 *data; \
|
||||||
vfs301_proto_generate(type, subtype, usb_send_buf, &len); \
|
gssize len; \
|
||||||
usb_send(devh, usb_send_buf, len); \
|
data = vfs301_proto_generate (type, subtype, &len); \
|
||||||
|
usb_send (dev, data, len, NULL); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define RAW_DATA(x) x, sizeof (x)
|
#define RAW_DATA(x) x, sizeof (x)
|
||||||
|
|
||||||
#define IS_VFS301_FP_SEQ_START(b) ((b[0] == 0x01) && (b[1] == 0xfe))
|
#define IS_VFS301_FP_SEQ_START(b) ((b[0] == 0x01) && (b[1] == 0xfe))
|
||||||
|
|
||||||
static int vfs301_proto_process_data(int first_block, vfs301_dev_t *dev)
|
static int
|
||||||
|
vfs301_proto_process_data (FpDeviceVfs301 *dev, int first_block, const guint8 *buf, gint len)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
const unsigned char *buf = dev->recv_buf;
|
|
||||||
int len = dev->recv_len;
|
|
||||||
|
|
||||||
if (first_block) {
|
if (first_block)
|
||||||
|
{
|
||||||
g_assert (len >= VFS301_FP_FRAME_SIZE);
|
g_assert (len >= VFS301_FP_FRAME_SIZE);
|
||||||
|
|
||||||
/* Skip bytes until start_sequence is found */
|
/* Skip bytes until start_sequence is found */
|
||||||
for (i = 0; i < VFS301_FP_FRAME_SIZE; i++, buf++, len--) {
|
for (i = 0; i < VFS301_FP_FRAME_SIZE; i++, buf++, len--)
|
||||||
if (IS_VFS301_FP_SEQ_START (buf))
|
if (IS_VFS301_FP_SEQ_START (buf))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return img_process_data (first_block, dev, buf, len);
|
return img_process_data (first_block, dev, buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
void vfs301_proto_request_fingerprint(
|
void
|
||||||
struct libusb_device_handle *devh, vfs301_dev_t *dev)
|
vfs301_proto_request_fingerprint (FpDeviceVfs301 *dev)
|
||||||
{
|
{
|
||||||
USB_SEND (0x0220, 0xFA00);
|
USB_SEND (0x0220, 0xFA00);
|
||||||
USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 000000000000 */
|
USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 000000000000 */
|
||||||
}
|
}
|
||||||
|
|
||||||
int vfs301_proto_peek_event(
|
int
|
||||||
struct libusb_device_handle *devh, vfs301_dev_t *dev)
|
vfs301_proto_peek_event (FpDeviceVfs301 *dev)
|
||||||
{
|
{
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
FpiUsbTransfer *transfer;
|
||||||
|
|
||||||
const char no_event[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
const char no_event[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
const char got_event[] = {0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00};
|
const char got_event[] = {0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00};
|
||||||
|
|
||||||
USB_SEND (0x17, -1);
|
USB_SEND (0x17, -1);
|
||||||
g_assert(USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 7) == 0);
|
usb_recv (dev, VFS301_RECEIVE_ENDPOINT_CTRL, 7, &transfer, &error);
|
||||||
|
|
||||||
if (memcmp(dev->recv_buf, no_event, sizeof(no_event)) == 0) {
|
/* XXX: This is obviously not a sane error handling! */
|
||||||
|
g_assert (!error);
|
||||||
|
|
||||||
|
if (memcmp (transfer->buffer, no_event, sizeof (no_event)) == 0)
|
||||||
return 0;
|
return 0;
|
||||||
} else if (memcmp(dev->recv_buf, got_event, sizeof(no_event)) == 0) {
|
else if (memcmp (transfer->buffer, got_event, sizeof (no_event)) == 0)
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
else
|
||||||
g_assert_not_reached ();
|
g_assert_not_reached ();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#define VARIABLE_ORDER(a, b) \
|
/* XXX: We sometimes need to receive data on from two endpoints at the same
|
||||||
|
* time. However, as this driver is currently all synchronous (yikes),
|
||||||
|
* we will run into timeouts randomly and need to then try again.
|
||||||
|
*/
|
||||||
|
#define PARALLEL_RECEIVE(e1, l1, e2, l2) \
|
||||||
{ \
|
{ \
|
||||||
int _rv = a;\
|
g_autoptr(GError) error = NULL; \
|
||||||
b; \
|
usb_recv (dev, e1, l1, NULL, &error); \
|
||||||
if (_rv == -7) \
|
usb_recv (dev, e2, l2, NULL, NULL); \
|
||||||
a; \
|
if (g_error_matches (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_TIMED_OUT)) \
|
||||||
|
usb_recv (dev, e1, l1, NULL, NULL); \
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vfs301_proto_process_event_cb(struct libusb_transfer *transfer)
|
static void
|
||||||
|
vfs301_proto_process_event_cb (FpiUsbTransfer *transfer,
|
||||||
|
FpDevice *device,
|
||||||
|
gpointer user_data, GError *error)
|
||||||
{
|
{
|
||||||
vfs301_dev_t *dev = transfer->user_data;
|
FpDeviceVfs301 *dev = user_data;
|
||||||
struct libusb_device_handle *devh = transfer->dev_handle;
|
|
||||||
|
|
||||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
if (error)
|
||||||
|
{
|
||||||
|
g_warning ("Error receiving data: %s", error->message);
|
||||||
|
g_error_free (error);
|
||||||
dev->recv_progress = VFS301_FAILURE;
|
dev->recv_progress = VFS301_FAILURE;
|
||||||
goto end;
|
return;
|
||||||
} else if (transfer->actual_length < dev->recv_exp_amt) {
|
}
|
||||||
|
else if (transfer->actual_length < transfer->length)
|
||||||
|
{
|
||||||
/* TODO: process the data anyway? */
|
/* TODO: process the data anyway? */
|
||||||
dev->recv_progress = VFS301_ENDED;
|
dev->recv_progress = VFS301_ENDED;
|
||||||
goto end;
|
return;
|
||||||
} else {
|
}
|
||||||
dev->recv_len = transfer->actual_length;
|
else
|
||||||
if (!vfs301_proto_process_data(dev->recv_exp_amt == VFS301_FP_RECV_LEN_1, dev)) {
|
{
|
||||||
|
FpiUsbTransfer *new;
|
||||||
|
if (!vfs301_proto_process_data (dev,
|
||||||
|
transfer->length == VFS301_FP_RECV_LEN_1,
|
||||||
|
transfer->buffer,
|
||||||
|
transfer->actual_length))
|
||||||
|
{
|
||||||
dev->recv_progress = VFS301_ENDED;
|
dev->recv_progress = VFS301_ENDED;
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev->recv_exp_amt = VFS301_FP_RECV_LEN_2;
|
|
||||||
libusb_fill_bulk_transfer(
|
|
||||||
transfer, devh, VFS301_RECEIVE_ENDPOINT_DATA,
|
|
||||||
dev->recv_buf, dev->recv_exp_amt,
|
|
||||||
vfs301_proto_process_event_cb, dev, VFS301_FP_RECV_TIMEOUT);
|
|
||||||
|
|
||||||
if (libusb_submit_transfer(transfer) < 0) {
|
|
||||||
printf("cb::continue fail\n");
|
|
||||||
dev->recv_progress = VFS301_FAILURE;
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
end:
|
new = fpi_usb_transfer_new (device);
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
|
fpi_usb_transfer_fill_bulk (new, VFS301_RECEIVE_ENDPOINT_DATA, VFS301_FP_RECV_LEN_2);
|
||||||
|
fpi_usb_transfer_submit (new, VFS301_FP_RECV_TIMEOUT, NULL,
|
||||||
|
vfs301_proto_process_event_cb, NULL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void vfs301_proto_process_event_start(
|
void
|
||||||
struct libusb_device_handle *devh, vfs301_dev_t *dev)
|
vfs301_proto_process_event_start (FpDeviceVfs301 *dev)
|
||||||
{
|
{
|
||||||
struct libusb_transfer *transfer;
|
FpiUsbTransfer *transfer;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Notes:
|
* Notes:
|
||||||
@@ -499,29 +572,16 @@ void vfs301_proto_process_event_start(
|
|||||||
USB_RECV (VFS301_RECEIVE_ENDPOINT_DATA, 64);
|
USB_RECV (VFS301_RECEIVE_ENDPOINT_DATA, 64);
|
||||||
|
|
||||||
/* now read the fingerprint data, while there are some */
|
/* now read the fingerprint data, while there are some */
|
||||||
transfer = libusb_alloc_transfer(0);
|
transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
|
||||||
if (!transfer) {
|
|
||||||
dev->recv_progress = VFS301_FAILURE;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev->recv_progress = VFS301_ONGOING;
|
dev->recv_progress = VFS301_ONGOING;
|
||||||
dev->recv_exp_amt = VFS301_FP_RECV_LEN_1;
|
|
||||||
|
|
||||||
libusb_fill_bulk_transfer(
|
fpi_usb_transfer_fill_bulk (transfer, VFS301_RECEIVE_ENDPOINT_DATA, VFS301_FP_RECV_LEN_1);
|
||||||
transfer, devh, VFS301_RECEIVE_ENDPOINT_DATA,
|
fpi_usb_transfer_submit (transfer, VFS301_FP_RECV_TIMEOUT, NULL,
|
||||||
dev->recv_buf, dev->recv_exp_amt,
|
vfs301_proto_process_event_cb, NULL);
|
||||||
vfs301_proto_process_event_cb, dev, VFS301_FP_RECV_TIMEOUT);
|
|
||||||
|
|
||||||
if (libusb_submit_transfer(transfer) < 0) {
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
dev->recv_progress = VFS301_FAILURE;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int /* vfs301_dev_t::recv_progress */ vfs301_proto_process_event_poll(
|
int
|
||||||
struct libusb_device_handle *devh, vfs301_dev_t *dev)
|
vfs301_proto_process_event_poll (FpDeviceVfs301 *dev)
|
||||||
{
|
{
|
||||||
if (dev->recv_progress != VFS301_ENDED)
|
if (dev->recv_progress != VFS301_ENDED)
|
||||||
return dev->recv_progress;
|
return dev->recv_progress;
|
||||||
@@ -531,21 +591,22 @@ int /* vfs301_dev_t::recv_progress */ vfs301_proto_process_event_poll(
|
|||||||
USB_SEND (0x04, -1);
|
USB_SEND (0x04, -1);
|
||||||
/* the following may come in random order, data may not come at all, don't
|
/* the following may come in random order, data may not come at all, don't
|
||||||
* try for too long... */
|
* try for too long... */
|
||||||
VARIABLE_ORDER(
|
PARALLEL_RECEIVE (
|
||||||
USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 2), /* 1204 */
|
VFS301_RECEIVE_ENDPOINT_CTRL, 2, /* 1204 */
|
||||||
USB_RECV(VFS301_RECEIVE_ENDPOINT_DATA, 16384)
|
VFS301_RECEIVE_ENDPOINT_DATA, 16384
|
||||||
);
|
);
|
||||||
|
|
||||||
USB_SEND (0x0220, 2);
|
USB_SEND (0x0220, 2);
|
||||||
VARIABLE_ORDER(
|
PARALLEL_RECEIVE (
|
||||||
USB_RECV(VFS301_RECEIVE_ENDPOINT_DATA, 5760), /* seems to always come */
|
VFS301_RECEIVE_ENDPOINT_DATA, 5760, /* seems to always come */
|
||||||
USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 2) /* 0000 */
|
VFS301_RECEIVE_ENDPOINT_CTRL, 2 /* 0000 */
|
||||||
);
|
);
|
||||||
|
|
||||||
return dev->recv_progress;
|
return dev->recv_progress;
|
||||||
}
|
}
|
||||||
|
|
||||||
void vfs301_proto_init(struct libusb_device_handle *devh, vfs301_dev_t *dev)
|
void
|
||||||
|
vfs301_proto_init (FpDeviceVfs301 *dev)
|
||||||
{
|
{
|
||||||
USB_SEND (0x01, -1);
|
USB_SEND (0x01, -1);
|
||||||
USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 38);
|
USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 38);
|
||||||
@@ -556,14 +617,14 @@ void vfs301_proto_init(struct libusb_device_handle *devh, vfs301_dev_t *dev)
|
|||||||
USB_SEND (0x19, -1);
|
USB_SEND (0x19, -1);
|
||||||
USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 64);
|
USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 64);
|
||||||
USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 4); /* 6BB4D0BC */
|
USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 4); /* 6BB4D0BC */
|
||||||
usb_send(devh, RAW_DATA(vfs301_06_1));
|
usb_send (dev, RAW_DATA (vfs301_06_1), NULL);
|
||||||
USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */
|
USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */
|
||||||
|
|
||||||
USB_SEND (0x01, -1);
|
USB_SEND (0x01, -1);
|
||||||
USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 38);
|
USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 38);
|
||||||
USB_SEND (0x1A, -1);
|
USB_SEND (0x1A, -1);
|
||||||
USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */
|
USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */
|
||||||
usb_send(devh, RAW_DATA(vfs301_06_2));
|
usb_send (dev, RAW_DATA (vfs301_06_2), NULL);
|
||||||
USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */
|
USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */
|
||||||
USB_SEND (0x0220, 1);
|
USB_SEND (0x0220, 1);
|
||||||
USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */
|
USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */
|
||||||
@@ -572,7 +633,7 @@ void vfs301_proto_init(struct libusb_device_handle *devh, vfs301_dev_t *dev)
|
|||||||
|
|
||||||
USB_SEND (0x1A, -1);
|
USB_SEND (0x1A, -1);
|
||||||
USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */
|
USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */
|
||||||
usb_send(devh, RAW_DATA(vfs301_06_3));
|
usb_send (dev, RAW_DATA (vfs301_06_3), NULL);
|
||||||
USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */
|
USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */
|
||||||
|
|
||||||
USB_SEND (0x01, -1);
|
USB_SEND (0x01, -1);
|
||||||
@@ -598,29 +659,29 @@ void vfs301_proto_init(struct libusb_device_handle *devh, vfs301_dev_t *dev)
|
|||||||
USB_SEND (0x02D0, 7);
|
USB_SEND (0x02D0, 7);
|
||||||
USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */
|
USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */
|
||||||
USB_RECV (VFS301_RECEIVE_ENDPOINT_DATA, 832);
|
USB_RECV (VFS301_RECEIVE_ENDPOINT_DATA, 832);
|
||||||
usb_send(devh, RAW_DATA(vfs301_12));
|
usb_send (dev, RAW_DATA (vfs301_12), NULL);
|
||||||
USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */
|
USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */
|
||||||
|
|
||||||
USB_SEND (0x1A, -1);
|
USB_SEND (0x1A, -1);
|
||||||
USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */
|
USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */
|
||||||
usb_send(devh, RAW_DATA(vfs301_06_2));
|
usb_send (dev, RAW_DATA (vfs301_06_2), NULL);
|
||||||
USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */
|
USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */
|
||||||
USB_SEND (0x0220, 2);
|
USB_SEND (0x0220, 2);
|
||||||
VARIABLE_ORDER(
|
PARALLEL_RECEIVE (
|
||||||
USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 2), /* 0000 */
|
VFS301_RECEIVE_ENDPOINT_CTRL, 2, /* 0000 */
|
||||||
USB_RECV(VFS301_RECEIVE_ENDPOINT_DATA, 5760)
|
VFS301_RECEIVE_ENDPOINT_DATA, 5760
|
||||||
);
|
);
|
||||||
|
|
||||||
USB_SEND (0x1A, -1);
|
USB_SEND (0x1A, -1);
|
||||||
USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */
|
USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */
|
||||||
usb_send(devh, RAW_DATA(vfs301_06_1));
|
usb_send (dev, RAW_DATA (vfs301_06_1), NULL);
|
||||||
USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */
|
USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */
|
||||||
|
|
||||||
USB_SEND (0x1A, -1);
|
USB_SEND (0x1A, -1);
|
||||||
USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */
|
USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */
|
||||||
usb_send(devh, RAW_DATA(vfs301_06_4));
|
usb_send (dev, RAW_DATA (vfs301_06_4), NULL);
|
||||||
USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */
|
USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */
|
||||||
usb_send(devh, RAW_DATA(vfs301_24)); /* turns on white */
|
usb_send (dev, RAW_DATA (vfs301_24), NULL); /* turns on white */
|
||||||
USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */
|
USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */
|
||||||
|
|
||||||
USB_SEND (0x01, -1);
|
USB_SEND (0x01, -1);
|
||||||
@@ -631,6 +692,7 @@ void vfs301_proto_init(struct libusb_device_handle *devh, vfs301_dev_t *dev)
|
|||||||
USB_RECV (VFS301_RECEIVE_ENDPOINT_DATA, 5760);
|
USB_RECV (VFS301_RECEIVE_ENDPOINT_DATA, 5760);
|
||||||
}
|
}
|
||||||
|
|
||||||
void vfs301_proto_deinit(struct libusb_device_handle *devh, vfs301_dev_t *dev)
|
void
|
||||||
|
vfs301_proto_deinit (FpDeviceVfs301 *dev)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,137 +0,0 @@
|
|||||||
/*
|
|
||||||
* vfs301/vfs300 fingerprint reader driver
|
|
||||||
* https://github.com/andree182/vfs301
|
|
||||||
*
|
|
||||||
* Copyright (c) 2011-2012 Andrej Krutak <dev@andree.sk>
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
#include <libusb-1.0/libusb.h>
|
|
||||||
|
|
||||||
enum {
|
|
||||||
VFS301_DEFAULT_WAIT_TIMEOUT = 300,
|
|
||||||
|
|
||||||
VFS301_SEND_ENDPOINT = 0x01,
|
|
||||||
VFS301_RECEIVE_ENDPOINT_CTRL = 0x81,
|
|
||||||
VFS301_RECEIVE_ENDPOINT_DATA = 0x82
|
|
||||||
};
|
|
||||||
|
|
||||||
#define VFS301_FP_RECV_LEN_1 (84032)
|
|
||||||
#define VFS301_FP_RECV_LEN_2 (84096)
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
/* buffer for received data */
|
|
||||||
unsigned char recv_buf[0x20000];
|
|
||||||
int recv_len;
|
|
||||||
|
|
||||||
/* buffer to hold raw scanlines */
|
|
||||||
unsigned char *scanline_buf;
|
|
||||||
int scanline_count;
|
|
||||||
|
|
||||||
enum {
|
|
||||||
VFS301_ONGOING = 0,
|
|
||||||
VFS301_ENDED = 1,
|
|
||||||
VFS301_FAILURE = -1
|
|
||||||
} recv_progress;
|
|
||||||
int recv_exp_amt;
|
|
||||||
} vfs301_dev_t;
|
|
||||||
|
|
||||||
enum {
|
|
||||||
/* Width of the scanned data in px */
|
|
||||||
VFS301_FP_WIDTH = 200,
|
|
||||||
|
|
||||||
/* sizeof(fp_line_t) */
|
|
||||||
VFS301_FP_FRAME_SIZE = 288,
|
|
||||||
/* Width of output line */
|
|
||||||
#ifndef OUTPUT_RAW
|
|
||||||
VFS301_FP_OUTPUT_WIDTH = VFS301_FP_WIDTH,
|
|
||||||
#else
|
|
||||||
VFS301_FP_OUTPUT_WIDTH = VFS301_FP_FRAME_SIZE,
|
|
||||||
#endif
|
|
||||||
|
|
||||||
VFS301_FP_SUM_LINES = 3,
|
|
||||||
|
|
||||||
#ifdef SCAN_FINISH_DETECTION
|
|
||||||
/* TODO: The following changes (seen ~60 and ~80) In that
|
|
||||||
* case we'll need to calibrate this from empty data somehow... */
|
|
||||||
VFS301_FP_SUM_MEDIAN = 60,
|
|
||||||
VFS301_FP_SUM_EMPTY_RANGE = 5,
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Minimum average difference between returned lines */
|
|
||||||
VFS301_FP_LINE_DIFF_THRESHOLD = 15,
|
|
||||||
|
|
||||||
/* Maximum waiting time for a single fingerprint frame */
|
|
||||||
VFS301_FP_RECV_TIMEOUT = 2000
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Arrays of this structure is returned during the initialization as a response
|
|
||||||
* to the 0x02D0 messages.
|
|
||||||
* It seems to be always the same - what is it for? Some kind of confirmation?
|
|
||||||
*/
|
|
||||||
typedef struct {
|
|
||||||
unsigned char sync_0x01;
|
|
||||||
unsigned char sync_0xfe;
|
|
||||||
|
|
||||||
unsigned char counter_lo;
|
|
||||||
unsigned char counter_hi; /* FIXME ? */
|
|
||||||
|
|
||||||
unsigned char flags[3];
|
|
||||||
|
|
||||||
unsigned char sync_0x00;
|
|
||||||
|
|
||||||
unsigned char scan[VFS301_FP_WIDTH];
|
|
||||||
} vfs301_init_line_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
unsigned char sync_0x01;
|
|
||||||
unsigned char sync_0xfe;
|
|
||||||
|
|
||||||
unsigned char counter_lo;
|
|
||||||
unsigned char counter_hi;
|
|
||||||
|
|
||||||
unsigned char sync_0x08[2]; /* XXX: always? 0x08 0x08 */
|
|
||||||
/* 0x08 | 0x18 - Looks like 0x08 marks good quality lines */
|
|
||||||
unsigned char flag_1;
|
|
||||||
unsigned char sync_0x00;
|
|
||||||
|
|
||||||
unsigned char scan[VFS301_FP_WIDTH];
|
|
||||||
|
|
||||||
/* A offseted, stretched, inverted copy of scan... probably could
|
|
||||||
* serve finger motion speed detection?
|
|
||||||
* Seems to be subdivided to some 10B + 53B + 1B blocks */
|
|
||||||
unsigned char mirror[64];
|
|
||||||
|
|
||||||
/* Some kind of sum of the scan, very low contrast */
|
|
||||||
unsigned char sum1[2];
|
|
||||||
unsigned char sum2[11];
|
|
||||||
unsigned char sum3[3];
|
|
||||||
} vfs301_line_t;
|
|
||||||
|
|
||||||
void vfs301_proto_init(struct libusb_device_handle *devh, vfs301_dev_t *dev);
|
|
||||||
void vfs301_proto_deinit(struct libusb_device_handle *devh, vfs301_dev_t *dev);
|
|
||||||
|
|
||||||
void vfs301_proto_request_fingerprint(
|
|
||||||
struct libusb_device_handle *devh, vfs301_dev_t *dev);
|
|
||||||
|
|
||||||
/** returns 0 if no event is ready, or 1 if there is one... */
|
|
||||||
int vfs301_proto_peek_event(
|
|
||||||
struct libusb_device_handle *devh, vfs301_dev_t *dev);
|
|
||||||
void vfs301_proto_process_event_start(
|
|
||||||
struct libusb_device_handle *devh, vfs301_dev_t *dev);
|
|
||||||
int vfs301_proto_process_event_poll(
|
|
||||||
struct libusb_device_handle *devh, vfs301_dev_t *dev);
|
|
||||||
|
|
||||||
void vfs301_extract_image(vfs301_dev_t *vfs, unsigned char *output, int *output_height);
|
|
||||||
@@ -1147,7 +1147,7 @@ static const unsigned char vfs301_24[] = { /* 119 B */
|
|||||||
*
|
*
|
||||||
* The contents of PACKET() inside this blob seems to be some kind
|
* The contents of PACKET() inside this blob seems to be some kind
|
||||||
* of a micro-program, which specifies which columns contain what. LE seems
|
* of a micro-program, which specifies which columns contain what. LE seems
|
||||||
* to be used also here. Not neccessarily is 1 output column described
|
* to be used also here. Not necessarily is 1 output column described
|
||||||
* by 1 operation. For example the vfs301_line_t::sum section seems
|
* by 1 operation. For example the vfs301_line_t::sum section seems
|
||||||
* to perform 2 operations for each column - probably some kind of diff between
|
* to perform 2 operations for each column - probably some kind of diff between
|
||||||
* input lines?
|
* input lines?
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#ifndef __VFS5011_PROTO_H
|
#pragma once
|
||||||
#define __VFS5011_PROTO_H
|
|
||||||
|
|
||||||
#define VFS5011_LINE_SIZE 240
|
#define VFS5011_LINE_SIZE 240
|
||||||
#define VFS5011_IMAGE_WIDTH 160
|
#define VFS5011_IMAGE_WIDTH 160
|
||||||
@@ -7,10 +6,10 @@
|
|||||||
enum {
|
enum {
|
||||||
VFS5011_DEFAULT_WAIT_TIMEOUT = 3000,
|
VFS5011_DEFAULT_WAIT_TIMEOUT = 3000,
|
||||||
|
|
||||||
VFS5011_OUT_ENDPOINT = 1 | LIBUSB_ENDPOINT_OUT,
|
VFS5011_OUT_ENDPOINT = 1 | FPI_USB_ENDPOINT_OUT,
|
||||||
VFS5011_IN_ENDPOINT_CTRL = 1 | LIBUSB_ENDPOINT_IN,
|
VFS5011_IN_ENDPOINT_CTRL = 1 | FPI_USB_ENDPOINT_IN,
|
||||||
VFS5011_IN_ENDPOINT_DATA = 2 | LIBUSB_ENDPOINT_IN,
|
VFS5011_IN_ENDPOINT_DATA = 2 | FPI_USB_ENDPOINT_IN,
|
||||||
VFS5011_IN_ENDPOINT_CTRL2 = 3 | LIBUSB_ENDPOINT_IN,
|
VFS5011_IN_ENDPOINT_CTRL2 = 3 | FPI_USB_ENDPOINT_IN,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
@@ -6182,5 +6181,3 @@ static unsigned char vfs5011_prepare_04[] = { /* 2903 B */
|
|||||||
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
||||||
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||