mirror of
https://gitlab.freedesktop.org/libfprint/libfprint.git
synced 2025-11-15 07:38:12 +00:00
Compare commits
433 Commits
V_0_6_0
...
libfprint-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
823f2c1067 | ||
|
|
19732341d6 | ||
|
|
0e44eb4c1c | ||
|
|
50461b4d7d | ||
|
|
c11126181e | ||
|
|
658c301e3c | ||
|
|
dce52ed081 | ||
|
|
f309f586c9 | ||
|
|
ae1b10dba8 | ||
|
|
860a256f4b | ||
|
|
cb2f46ed08 | ||
|
|
13deaa66fd | ||
|
|
3597a5b0ed | ||
|
|
0352995cb3 | ||
|
|
e9041da7f4 | ||
|
|
252180e088 | ||
|
|
6361c208bd | ||
|
|
2ef8ace543 | ||
|
|
0400bcc85e | ||
|
|
76db6a5a16 | ||
|
|
5b171f9577 | ||
|
|
4cec28416e | ||
|
|
3b32baccf6 | ||
|
|
16875d7776 | ||
|
|
a9600e23a1 | ||
|
|
a4b6813ebf | ||
|
|
ef90938eb9 | ||
|
|
66891274a7 | ||
|
|
f52276bd06 | ||
|
|
7dce8dbfaa | ||
|
|
3b757ee738 | ||
|
|
0a45ed7af6 | ||
|
|
1db2dc3f58 | ||
|
|
953c75575b | ||
|
|
8c7ff259af | ||
|
|
3e666130c2 | ||
|
|
2babfa0625 | ||
|
|
83af40679a | ||
|
|
ce31c1d704 | ||
|
|
b20a74a22c | ||
|
|
66461e4c81 | ||
|
|
6ba9439bbb | ||
|
|
6764ec79ae | ||
|
|
6f4c378933 | ||
|
|
b121fa2cc9 | ||
|
|
ca26e85fd4 | ||
|
|
0714380360 | ||
|
|
b9af7952a4 | ||
|
|
ea6820ed51 | ||
|
|
a1e46de462 | ||
|
|
1abe213844 | ||
|
|
0372ae8ba5 | ||
|
|
a1e69a0e9d | ||
|
|
49e1e98914 | ||
|
|
34b316d7d5 | ||
|
|
9abc6791c7 | ||
|
|
5459823667 | ||
|
|
4fa8c5ec47 | ||
|
|
239034714f | ||
|
|
8a3a974ea3 | ||
|
|
db607c4a6f | ||
|
|
a53f07a8f6 | ||
|
|
c3e996b96c | ||
|
|
a218437cf4 | ||
|
|
0add0ca9b1 | ||
|
|
eaa4aa964c | ||
|
|
74bb899ce2 | ||
|
|
69fe7a1b8c | ||
|
|
ce856efa25 | ||
|
|
b54514df6e | ||
|
|
551616c3ab | ||
|
|
cec307ce7f | ||
|
|
e7bc8e03fc | ||
|
|
9a025bde8b | ||
|
|
6845e400cd | ||
|
|
25d0fa42e2 | ||
|
|
52208a6606 | ||
|
|
6725b22fd4 | ||
|
|
21bac43015 | ||
|
|
0ddd11f81b | ||
|
|
6d47c44335 | ||
|
|
3cbc908a6e | ||
|
|
95b1e75f1b | ||
|
|
bcfe0ad12c | ||
|
|
2088a6177f | ||
|
|
c9733d27df | ||
|
|
dd24cf57c6 | ||
|
|
451a4c0969 | ||
|
|
dabcae7b4d | ||
|
|
eae5721f8e | ||
|
|
ce1a675dd5 | ||
|
|
6ba1016024 | ||
|
|
b5f175b78e | ||
|
|
aff7efd891 | ||
|
|
1d00c2d4b4 | ||
|
|
61483a4c47 | ||
|
|
2b21430abe | ||
|
|
1781ad140e | ||
|
|
d2e3ad4dbc | ||
|
|
7615aaef7a | ||
|
|
92e3168309 | ||
|
|
ca148cbcf1 | ||
|
|
e57f037a10 | ||
|
|
46ad86fab2 | ||
|
|
511e164f17 | ||
|
|
6f18fc4bf4 | ||
|
|
8ca34303f2 | ||
|
|
882fc8ab54 | ||
|
|
9e5ae25abf | ||
|
|
9316dfed2e | ||
|
|
702932c69b | ||
|
|
29461fa910 | ||
|
|
f7173e6645 | ||
|
|
11b11a9d71 | ||
|
|
9da69dfc36 | ||
|
|
e5f4021a4f | ||
|
|
4dcbc6a3aa | ||
|
|
7a72d8fd58 | ||
|
|
5edfd55e00 | ||
|
|
2951daaa01 | ||
|
|
23f7c4aaf7 | ||
|
|
3dc5c4a6de | ||
|
|
a97ae3bc35 | ||
|
|
53d2fb3ad2 | ||
|
|
4f7e507716 | ||
|
|
f2e3a840db | ||
|
|
f45c18116a | ||
|
|
2365c608f9 | ||
|
|
6c6daaa619 | ||
|
|
857a399bfa | ||
|
|
6e230f0a07 | ||
|
|
7402401057 | ||
|
|
fe17dfe01d | ||
|
|
4885b38be5 | ||
|
|
5d4a5981d0 | ||
|
|
0fcb4533b5 | ||
|
|
422f81b60c | ||
|
|
e0d2f3ae53 | ||
|
|
531d9048b3 | ||
|
|
18495d122d | ||
|
|
9bcacd97df | ||
|
|
d91eae26e5 | ||
|
|
d113ed9d83 | ||
|
|
e113754312 | ||
|
|
b1afa9da5d | ||
|
|
700c5791f8 | ||
|
|
97d0a6dfe6 | ||
|
|
a54d020c97 | ||
|
|
36b696f433 | ||
|
|
f42cd6eefd | ||
|
|
46ebb39f65 | ||
|
|
c88a51cce8 | ||
|
|
3a7b03f022 | ||
|
|
94450a1d74 | ||
|
|
c35ad20249 | ||
|
|
5e8b4a81e9 | ||
|
|
21a779235d | ||
|
|
1006467f33 | ||
|
|
cffe49de5c | ||
|
|
7962d8cdab | ||
|
|
36dba33808 | ||
|
|
c273908471 | ||
|
|
bf8661bf45 | ||
|
|
499b522183 | ||
|
|
13bfe7a65c | ||
|
|
e90ec04441 | ||
|
|
a59a5caaf3 | ||
|
|
5b9f81fb46 | ||
|
|
d3aaebb352 | ||
|
|
a99f920fe0 | ||
|
|
fb5527c58c | ||
|
|
fcd3c1dd89 | ||
|
|
3a9500be67 | ||
|
|
1d93b86569 | ||
|
|
aca2cd41d8 | ||
|
|
1035f733aa | ||
|
|
2818d94010 | ||
|
|
1d1c34eb60 | ||
|
|
ca06fae22e | ||
|
|
36f527269b | ||
|
|
7cfe20e07f | ||
|
|
1fd82b5162 | ||
|
|
0ace5f64f8 | ||
|
|
e532524c7e | ||
|
|
ebd96f892e | ||
|
|
4b9b34fa4d | ||
|
|
bcc1e7ae73 | ||
|
|
27accf42f2 | ||
|
|
96f2e07cdd | ||
|
|
192c4f3cfc | ||
|
|
cb274032da | ||
|
|
b890fa56d8 | ||
|
|
b817b46494 | ||
|
|
49ba59369a | ||
|
|
d09cb88e9a | ||
|
|
44c3f4f772 | ||
|
|
948a67a51f | ||
|
|
de79609550 | ||
|
|
d18e10535e | ||
|
|
2954583373 | ||
|
|
ccdecdea11 | ||
|
|
946388d1e9 | ||
|
|
10ae8ffb55 | ||
|
|
bdba9990fb | ||
|
|
50166e88c0 | ||
|
|
f2bc826a20 | ||
|
|
ac48d66203 | ||
|
|
f68e7fcb9f | ||
|
|
0c3a22758b | ||
|
|
9cc859a318 | ||
|
|
7dfc8f3364 | ||
|
|
e397571f83 | ||
|
|
d34d7c26de | ||
|
|
77defa1d8b | ||
|
|
5d01497b8b | ||
|
|
cb8732b255 | ||
|
|
3f64b2ea5a | ||
|
|
57b38a2876 | ||
|
|
058f91909d | ||
|
|
4f75e63e25 | ||
|
|
2e50ff5e7c | ||
|
|
0b7477e72c | ||
|
|
4dc8aa6dfa | ||
|
|
161c3ccf1c | ||
|
|
170da7fec1 | ||
|
|
d7af9a4498 | ||
|
|
3cb3b1d63a | ||
|
|
fc66919e1f | ||
|
|
de5b4e7dcb | ||
|
|
561576961c | ||
|
|
2946dabd24 | ||
|
|
969eefc81f | ||
|
|
efee7262b6 | ||
|
|
1102d6e478 | ||
|
|
603aab0a81 | ||
|
|
10e934e234 | ||
|
|
48b9e6c517 | ||
|
|
5ae2ef5407 | ||
|
|
cafa05dab5 | ||
|
|
6345835b02 | ||
|
|
1d453b5732 | ||
|
|
d3a1b86ea4 | ||
|
|
bb27ca5720 | ||
|
|
065c0b6202 | ||
|
|
b4819701b4 | ||
|
|
daed05755a | ||
|
|
fb192f706c | ||
|
|
350b0a38e2 | ||
|
|
9ccbda4a40 | ||
|
|
821cbae187 | ||
|
|
528f3556ea | ||
|
|
489afea605 | ||
|
|
688a133f3f | ||
|
|
0cd37b0142 | ||
|
|
9fb789dc78 | ||
|
|
770444af55 | ||
|
|
703d9b2a07 | ||
|
|
a96509f286 | ||
|
|
8553f2e41c | ||
|
|
56c96dde8b | ||
|
|
9793d60c5a | ||
|
|
4ff97e7cbd | ||
|
|
75fe328f64 | ||
|
|
b28b006d61 | ||
|
|
c3b1c982bc | ||
|
|
b098399bbc | ||
|
|
65bbdff3fc | ||
|
|
fba3e682ea | ||
|
|
bccff4ffef | ||
|
|
9843c2d764 | ||
|
|
c9abbec48a | ||
|
|
bc79f9504b | ||
|
|
626b0f1a8f | ||
|
|
da95af0f48 | ||
|
|
28b6f643d8 | ||
|
|
22277c7277 | ||
|
|
19e7b217c1 | ||
|
|
29d3541b74 | ||
|
|
b9e5b3a55c | ||
|
|
b1ac865abd | ||
|
|
21504c0621 | ||
|
|
056ea541dd | ||
|
|
871fddf5fb | ||
|
|
c284858d06 | ||
|
|
bb4d888661 | ||
|
|
ff77cfc9b5 | ||
|
|
80f91ecb7b | ||
|
|
6cb77465ab | ||
|
|
6f6127cbb6 | ||
|
|
e1d85fb636 | ||
|
|
74b5c92787 | ||
|
|
ac1f97e2eb | ||
|
|
40f486b108 | ||
|
|
b62e67401c | ||
|
|
dd0a0134a6 | ||
|
|
5e24000799 | ||
|
|
c5cdfcb120 | ||
|
|
549a6694d2 | ||
|
|
14e34e1d15 | ||
|
|
e5393bf46a | ||
|
|
878a201bb1 | ||
|
|
b0e4619e0a | ||
|
|
aec65777a7 | ||
|
|
31bad8ddd2 | ||
|
|
79d65c907f | ||
|
|
92231d984f | ||
|
|
2fbc77955e | ||
|
|
c91819f551 | ||
|
|
b3f6ff5a36 | ||
|
|
52f84bee3c | ||
|
|
dda6857fee | ||
|
|
0215483fb3 | ||
|
|
37bb59df13 | ||
|
|
db34837d2d | ||
|
|
ba49677794 | ||
|
|
1a376c1bfa | ||
|
|
ef807d9d0e | ||
|
|
2a4893d946 | ||
|
|
cee061b363 | ||
|
|
1bbdf304ab | ||
|
|
6155068f9e | ||
|
|
0c4e3bb1c4 | ||
|
|
4547ff0c19 | ||
|
|
b7cce4d91d | ||
|
|
475250ce71 | ||
|
|
f40f231a63 | ||
|
|
d83d92adf2 | ||
|
|
d15282bff1 | ||
|
|
00637c4f0b | ||
|
|
2e035a7f45 | ||
|
|
17577175f8 | ||
|
|
933fab6ed4 | ||
|
|
7e5661caff | ||
|
|
19dfb138a6 | ||
|
|
0930f2614c | ||
|
|
1b20521e5c | ||
|
|
0e351db91a | ||
|
|
9cca501650 | ||
|
|
2481cbe4ab | ||
|
|
bc3959d1e0 | ||
|
|
1ac815e457 | ||
|
|
55b83062d0 | ||
|
|
391f77ce5e | ||
|
|
bc30a3d2e5 | ||
|
|
ff5de4ff03 | ||
|
|
f433a4d67c | ||
|
|
994061af44 | ||
|
|
501020921e | ||
|
|
53c09405b2 | ||
|
|
1f0079a274 | ||
|
|
15afe43cf0 | ||
|
|
eb8f7ba3b2 | ||
|
|
901a6f7fed | ||
|
|
fc92f62136 | ||
|
|
ff09456cf5 | ||
|
|
32fcfde86b | ||
|
|
363a1b3371 | ||
|
|
c376c6fb02 | ||
|
|
8e6e23b8d0 | ||
|
|
63e5d56441 | ||
|
|
e9bfd943fc | ||
|
|
614e2286c2 | ||
|
|
768a74c4bf | ||
|
|
612e9e11de | ||
|
|
06c72d54be | ||
|
|
be68bacc94 | ||
|
|
317d7bc988 | ||
|
|
b44e417bca | ||
|
|
9d67ce484d | ||
|
|
78b8602cf6 | ||
|
|
83a0a7681b | ||
|
|
c5e0e41ce7 | ||
|
|
b3fe4a1e91 | ||
|
|
f59bf389d9 | ||
|
|
231b8f9f92 | ||
|
|
dac153d24a | ||
|
|
3661d146a7 | ||
|
|
3bf55a3e07 | ||
|
|
5226467fc2 | ||
|
|
54deaa1b24 | ||
|
|
7ff667f58d | ||
|
|
58ba9b02ed | ||
|
|
d35da0ce99 | ||
|
|
041e6a1078 | ||
|
|
1c73c36ed7 | ||
|
|
69de32f700 | ||
|
|
4bfee76ead | ||
|
|
4d7afd9b4f | ||
|
|
cfe60c0640 | ||
|
|
d82847a6b4 | ||
|
|
5a7e6e07ff | ||
|
|
2162aa9f48 | ||
|
|
a1f36c71c9 | ||
|
|
e4eedef27e | ||
|
|
5e29695969 | ||
|
|
49a46668ad | ||
|
|
76269decdd | ||
|
|
8454a25ecf | ||
|
|
a0bbbd7d32 | ||
|
|
12f6dae8cd | ||
|
|
9570c36fd4 | ||
|
|
487dae0d2f | ||
|
|
d71018bd8f | ||
|
|
61fa57b05d | ||
|
|
fc1781e317 | ||
|
|
ffef6c2bcc | ||
|
|
67d29f7936 | ||
|
|
9437c98d54 | ||
|
|
f7d00a828d | ||
|
|
0f0a4b2da6 | ||
|
|
c9cdbaf880 | ||
|
|
83f29dad9f | ||
|
|
c2a11c5918 | ||
|
|
3746b2ad5c | ||
|
|
b51fa446e3 | ||
|
|
6fc5293e83 | ||
|
|
aab3daa28b | ||
|
|
e40f7bd1f7 | ||
|
|
6664f87d8f | ||
|
|
6e8d5cd6a1 | ||
|
|
9f7e1ecf40 | ||
|
|
d9567002e4 | ||
|
|
a656a4a9f3 | ||
|
|
2944a35e74 | ||
|
|
391373fb0c | ||
|
|
985e8c4577 | ||
|
|
bd0d4258e4 | ||
|
|
9bbd9b208a | ||
|
|
59fe0fb699 | ||
|
|
f1fdd71613 | ||
|
|
bb66780cb5 | ||
|
|
45fb6d7908 | ||
|
|
9f408bf51b |
113
.ci/check-abi
Executable file
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!')
|
||||||
71
.gitlab-ci.yml
Normal file
71
.gitlab-ci.yml
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
image: fedora:rawhide
|
||||||
|
stages:
|
||||||
|
- build
|
||||||
|
- test
|
||||||
|
|
||||||
|
variables:
|
||||||
|
DEPENDENCIES: libusb1-devel glib2-devel nss-devel pixman-devel systemd meson gtk-doc
|
||||||
|
gcc gcc-c++ glibc-devel libX11-devel libXv-devel gtk3-devel flatpak-builder
|
||||||
|
BUNDLE: "org.freedesktop.libfprint.Demo.flatpak"
|
||||||
|
LAST_ABI_BREAK: "056ea541ddc97f5806cffbd99a12dc87e4da3546"
|
||||||
|
|
||||||
|
.build_one_driver_template: &build_one_driver
|
||||||
|
script:
|
||||||
|
- dnf update -y --nogpgcheck && dnf install -y --nogpgcheck $DEPENDENCIES
|
||||||
|
# Build with a driver that doesn't need imaging, or nss
|
||||||
|
- meson -Ddrivers=elan . _build
|
||||||
|
- ninja -C _build
|
||||||
|
- rm -rf _build/
|
||||||
|
|
||||||
|
.build_template: &build
|
||||||
|
script:
|
||||||
|
- dnf update -y --nogpgcheck && dnf install -y --nogpgcheck $DEPENDENCIES
|
||||||
|
# And build with everything
|
||||||
|
- meson -Ddrivers=all . _build
|
||||||
|
- ninja -C _build
|
||||||
|
- ninja -C _build install
|
||||||
|
|
||||||
|
.build_template: &check_abi
|
||||||
|
script:
|
||||||
|
- dnf update -y --nogpgcheck && dnf install -y --nogpgcheck $DEPENDENCIES doxygen libabigail git
|
||||||
|
- ./.ci/check-abi ${LAST_ABI_BREAK} $(git rev-parse HEAD)
|
||||||
|
|
||||||
|
build:
|
||||||
|
stage: build
|
||||||
|
<<: *build_one_driver
|
||||||
|
<<: *build
|
||||||
|
<<: *check_abi
|
||||||
|
|
||||||
|
.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:
|
||||||
|
image: registry.gitlab.gnome.org/gnome/gnome-runtime-images/gnome:master
|
||||||
|
stage: test
|
||||||
|
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
|
||||||
96
HACKING
96
HACKING
@@ -1,96 +0,0 @@
|
|||||||
Copyright notices
|
|
||||||
=================
|
|
||||||
|
|
||||||
If you make a contribution substantial enough to add or update a copyright
|
|
||||||
notice on a file, such notice must be mirrored in the AUTHORS file. This is
|
|
||||||
to make it easy for people to comply to section 6 of the LGPL, which states
|
|
||||||
that a "work that uses the Library" must include copyright notices from
|
|
||||||
this library. By providing them all in one place, hopefully we save such
|
|
||||||
users some time.
|
|
||||||
|
|
||||||
|
|
||||||
USB
|
|
||||||
===
|
|
||||||
|
|
||||||
At the time of development, there are no known consumer fingerprint readers
|
|
||||||
which do not operate over the USB bus. Therefore the library is designed around
|
|
||||||
the fact that each driver drivers USB devices, and each device is a USB device.
|
|
||||||
If we were to ever support a non-USB device, some rearchitecting would be
|
|
||||||
needed, but this would not be a substantial task.
|
|
||||||
|
|
||||||
|
|
||||||
GLib
|
|
||||||
====
|
|
||||||
|
|
||||||
Although the library uses GLib internally, libfprint is designed to provide
|
|
||||||
a completely neutral interface to it's application users. So, the public
|
|
||||||
APIs should never return GLib data types or anything like that.
|
|
||||||
|
|
||||||
|
|
||||||
Two-faced-ness
|
|
||||||
==============
|
|
||||||
|
|
||||||
Like any decent library, this one is designed to provide a stable and
|
|
||||||
documented API to it's users: applications. Clear distinction is made between
|
|
||||||
data available internally in the library, and data/functions available to
|
|
||||||
the applications.
|
|
||||||
|
|
||||||
This library is confused a little by the fact that there is another 'interface'
|
|
||||||
at hand: the internal interface provided to drivers. So, we effectively end
|
|
||||||
up with 2 APIs:
|
|
||||||
|
|
||||||
1. The external-facing API for applications
|
|
||||||
2. The internal API for fingerprint drivers
|
|
||||||
|
|
||||||
Non-static functions which are intended for internal use only are prepended
|
|
||||||
with the "fpi_" prefix.
|
|
||||||
|
|
||||||
|
|
||||||
API stability
|
|
||||||
=============
|
|
||||||
|
|
||||||
No API stability has been promised to anyone: go wild, there's no issue with
|
|
||||||
breaking APIs at this point in time.
|
|
||||||
|
|
||||||
|
|
||||||
Portability
|
|
||||||
===========
|
|
||||||
|
|
||||||
libfprint is primarily written for Linux. However, I'm interested in
|
|
||||||
supporting efforts to port this to other operating systems too.
|
|
||||||
|
|
||||||
You should ensure code is portable wherever possible. Try and use GLib rather
|
|
||||||
than OS-specific features.
|
|
||||||
|
|
||||||
Endianness must be considered in all code. libfprint must support both big-
|
|
||||||
and little-endian systems.
|
|
||||||
|
|
||||||
|
|
||||||
Coding Style
|
|
||||||
============
|
|
||||||
|
|
||||||
This project follows Linux kernel coding style but with a tab width of 4.
|
|
||||||
|
|
||||||
|
|
||||||
Documentation
|
|
||||||
=============
|
|
||||||
|
|
||||||
All additions of public API functions must be accompanied with doxygen
|
|
||||||
comments.
|
|
||||||
|
|
||||||
All changes which potentially change the behaviour of the public API must
|
|
||||||
be reflected by updating the appropriate doxygen comments.
|
|
||||||
|
|
||||||
|
|
||||||
Contributing
|
|
||||||
============
|
|
||||||
|
|
||||||
Patches should be sent to the fprint bugzilla:
|
|
||||||
https://bugs.freedesktop.org/enter_bug.cgi?product=libfprint
|
|
||||||
|
|
||||||
Information about libfprint development repositories can be found here:
|
|
||||||
http://www.freedesktop.org/wiki/Software/fprint/libfprint
|
|
||||||
|
|
||||||
If you're looking for ideas for things to work on, look at the TODO file or
|
|
||||||
grep the source code for FIXMEs.
|
|
||||||
|
|
||||||
73
HACKING.md
Normal file
73
HACKING.md
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
# Contributing to libfprint
|
||||||
|
|
||||||
|
## GLib
|
||||||
|
|
||||||
|
Although the library uses GLib internally, libfprint is designed to provide
|
||||||
|
a completely neutral interface to its application users. So, the public
|
||||||
|
APIs should never return GLib data types.
|
||||||
|
|
||||||
|
## License clarification
|
||||||
|
|
||||||
|
Although this library's license could allow for shims that hook up into
|
||||||
|
proprietary blobs to add driver support for some unsupported devices, the
|
||||||
|
intent of the original authors, and of current maintainers of the library,
|
||||||
|
was for this license to allow _integration into_ proprietary stacks, not
|
||||||
|
_integration of_ proprietary code in the library.
|
||||||
|
|
||||||
|
As such, no code to integrate proprietary drivers will be accepted in libfprint
|
||||||
|
upstream. Proprietary drivers would make it impossible to debug problems in
|
||||||
|
libfprint, as we wouldn't know what the proprietary driver does behind the
|
||||||
|
library's back. The closed source nature of drivers is usually used to hide
|
||||||
|
parts of the hardware setup, such as encryption keys, or protocols, in order
|
||||||
|
to protect the hardware's integrity. Unfortunately, this is only [security through
|
||||||
|
obscurity](https://en.wikipedia.org/wiki/Security_through_obscurity).
|
||||||
|
|
||||||
|
We however encourage potential contributors to take advantage of libfprint's
|
||||||
|
source availability to create such shims to make it easier to reverse-engineer
|
||||||
|
proprietary drivers in order to create new free software drivers, to the extent
|
||||||
|
permitted by local laws.
|
||||||
|
|
||||||
|
## Two-faced-ness
|
||||||
|
|
||||||
|
Like any decent library, this one is designed to provide a stable and
|
||||||
|
documented API to its users: applications. Clear distinction is made between
|
||||||
|
data available internally in the library, and data/functions available to
|
||||||
|
the applications.
|
||||||
|
|
||||||
|
This library is confused a little by the fact that there is another 'interface'
|
||||||
|
at hand: the internal interface provided to drivers. So, we effectively end
|
||||||
|
up with 2 APIs:
|
||||||
|
|
||||||
|
1. The [external-facing API for applications](libfprint/fprint.h)
|
||||||
|
2. The [internal API for fingerprint drivers](libfprint/drivers_api.h)
|
||||||
|
|
||||||
|
Non-static functions which are intended for internal use only are prepended
|
||||||
|
with the "fpi_" prefix.
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
All additions of public API functions must be accompanied with gtk-doc
|
||||||
|
comments.
|
||||||
|
|
||||||
|
All changes which potentially change the behaviour of the public API must
|
||||||
|
be reflected by updating the appropriate gtk-doc comments.
|
||||||
|
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Patches should be sent as merge requests to the gitlab page:
|
||||||
|
https://gitlab.freedesktop.org/libfprint/libfprint/merge_requests
|
||||||
|
|
||||||
|
Drivers are not usually written by libfprint developers, but when they
|
||||||
|
are, we require:
|
||||||
|
- 3 stand-alone devices. Not in a laptop or another embedded device, as
|
||||||
|
space is scarce, unless the device has special integration with that
|
||||||
|
hardware.
|
||||||
|
- specifications of the protocol.
|
||||||
|
|
||||||
|
If you are an end-user, you can file a feature request with the "Driver Request"
|
||||||
|
tag on [libfprint's issue page](https://gitlab.freedesktop.org/libfprint/libfprint/issues?scope=all&utf8=%E2%9C%93&state=opened&label_name[]=Driver%20Request),
|
||||||
|
or subscribe to an existing feature request there.
|
||||||
|
|
||||||
|
If you are an enterprising hacker, please file a new merge request with
|
||||||
|
the driver patches integrated.
|
||||||
238
INSTALL
238
INSTALL
@@ -1,234 +1,6 @@
|
|||||||
Installation Instructions
|
libfprint uses the Meson build system. See
|
||||||
*************************
|
http://mesonbuild.com/Quick-guide.html for details on how to
|
||||||
|
compile libfprint.
|
||||||
Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
|
|
||||||
2006 Free Software Foundation, Inc.
|
|
||||||
|
|
||||||
This file is free documentation; the Free Software Foundation gives
|
|
||||||
unlimited permission to copy, distribute and modify it.
|
|
||||||
|
|
||||||
Basic Installation
|
|
||||||
==================
|
|
||||||
|
|
||||||
Briefly, the shell commands `./configure; make; make install' should
|
|
||||||
configure, build, and install this package. The following
|
|
||||||
more-detailed instructions are generic; see the `README' file for
|
|
||||||
instructions specific to this package.
|
|
||||||
|
|
||||||
The `configure' shell script attempts to guess correct values for
|
|
||||||
various system-dependent variables used during compilation. It uses
|
|
||||||
those values to create a `Makefile' in each directory of the package.
|
|
||||||
It may also create one or more `.h' files containing system-dependent
|
|
||||||
definitions. Finally, it creates a shell script `config.status' that
|
|
||||||
you can run in the future to recreate the current configuration, and a
|
|
||||||
file `config.log' containing compiler output (useful mainly for
|
|
||||||
debugging `configure').
|
|
||||||
|
|
||||||
It can also use an optional file (typically called `config.cache'
|
|
||||||
and enabled with `--cache-file=config.cache' or simply `-C') that saves
|
|
||||||
the results of its tests to speed up reconfiguring. Caching is
|
|
||||||
disabled by default to prevent problems with accidental use of stale
|
|
||||||
cache files.
|
|
||||||
|
|
||||||
If you need to do unusual things to compile the package, please try
|
|
||||||
to figure out how `configure' could check whether to do them, and mail
|
|
||||||
diffs or instructions to the address given in the `README' so they can
|
|
||||||
be considered for the next release. If you are using the cache, and at
|
|
||||||
some point `config.cache' contains results you don't want to keep, you
|
|
||||||
may remove or edit it.
|
|
||||||
|
|
||||||
The file `configure.ac' (or `configure.in') is used to create
|
|
||||||
`configure' by a program called `autoconf'. You need `configure.ac' if
|
|
||||||
you want to change it or regenerate `configure' using a newer version
|
|
||||||
of `autoconf'.
|
|
||||||
|
|
||||||
The simplest way to compile this package is:
|
|
||||||
|
|
||||||
1. `cd' to the directory containing the package's source code and type
|
|
||||||
`./configure' to configure the package for your system.
|
|
||||||
|
|
||||||
Running `configure' might take a while. While running, it prints
|
|
||||||
some messages telling which features it is checking for.
|
|
||||||
|
|
||||||
2. Type `make' to compile the package.
|
|
||||||
|
|
||||||
3. Optionally, type `make check' to run any self-tests that come with
|
|
||||||
the package.
|
|
||||||
|
|
||||||
4. Type `make install' to install the programs and any data files and
|
|
||||||
documentation.
|
|
||||||
|
|
||||||
5. You can remove the program binaries and object files from the
|
|
||||||
source code directory by typing `make clean'. To also remove the
|
|
||||||
files that `configure' created (so you can compile the package for
|
|
||||||
a different kind of computer), type `make distclean'. There is
|
|
||||||
also a `make maintainer-clean' target, but that is intended mainly
|
|
||||||
for the package's developers. If you use it, you may have to get
|
|
||||||
all sorts of other programs in order to regenerate files that came
|
|
||||||
with the distribution.
|
|
||||||
|
|
||||||
Compilers and Options
|
|
||||||
=====================
|
|
||||||
|
|
||||||
Some systems require unusual options for compilation or linking that the
|
|
||||||
`configure' script does not know about. Run `./configure --help' for
|
|
||||||
details on some of the pertinent environment variables.
|
|
||||||
|
|
||||||
You can give `configure' initial values for configuration parameters
|
|
||||||
by setting variables in the command line or in the environment. Here
|
|
||||||
is an example:
|
|
||||||
|
|
||||||
./configure CC=c99 CFLAGS=-g LIBS=-lposix
|
|
||||||
|
|
||||||
*Note Defining Variables::, for more details.
|
|
||||||
|
|
||||||
Compiling For Multiple Architectures
|
|
||||||
====================================
|
|
||||||
|
|
||||||
You can compile the package for more than one kind of computer at the
|
|
||||||
same time, by placing the object files for each architecture in their
|
|
||||||
own directory. To do this, you can use GNU `make'. `cd' to the
|
|
||||||
directory where you want the object files and executables to go and run
|
|
||||||
the `configure' script. `configure' automatically checks for the
|
|
||||||
source code in the directory that `configure' is in and in `..'.
|
|
||||||
|
|
||||||
With a non-GNU `make', it is safer to compile the package for one
|
|
||||||
architecture at a time in the source code directory. After you have
|
|
||||||
installed the package for one architecture, use `make distclean' before
|
|
||||||
reconfiguring for another architecture.
|
|
||||||
|
|
||||||
Installation Names
|
|
||||||
==================
|
|
||||||
|
|
||||||
By default, `make install' installs the package's commands under
|
|
||||||
`/usr/local/bin', include files under `/usr/local/include', etc. You
|
|
||||||
can specify an installation prefix other than `/usr/local' by giving
|
|
||||||
`configure' the option `--prefix=PREFIX'.
|
|
||||||
|
|
||||||
You can specify separate installation prefixes for
|
|
||||||
architecture-specific files and architecture-independent files. If you
|
|
||||||
pass the option `--exec-prefix=PREFIX' to `configure', the package uses
|
|
||||||
PREFIX as the prefix for installing programs and libraries.
|
|
||||||
Documentation and other data files still use the regular prefix.
|
|
||||||
|
|
||||||
In addition, if you use an unusual directory layout you can give
|
|
||||||
options like `--bindir=DIR' to specify different values for particular
|
|
||||||
kinds of files. Run `configure --help' for a list of the directories
|
|
||||||
you can set and what kinds of files go in them.
|
|
||||||
|
|
||||||
If the package supports it, you can cause programs to be installed
|
|
||||||
with an extra prefix or suffix on their names by giving `configure' the
|
|
||||||
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
|
|
||||||
|
|
||||||
Optional Features
|
|
||||||
=================
|
|
||||||
|
|
||||||
Some packages pay attention to `--enable-FEATURE' options to
|
|
||||||
`configure', where FEATURE indicates an optional part of the package.
|
|
||||||
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
|
|
||||||
is something like `gnu-as' or `x' (for the X Window System). The
|
|
||||||
`README' should mention any `--enable-' and `--with-' options that the
|
|
||||||
package recognizes.
|
|
||||||
|
|
||||||
For packages that use the X Window System, `configure' can usually
|
|
||||||
find the X include and library files automatically, but if it doesn't,
|
|
||||||
you can use the `configure' options `--x-includes=DIR' and
|
|
||||||
`--x-libraries=DIR' to specify their locations.
|
|
||||||
|
|
||||||
Specifying the System Type
|
|
||||||
==========================
|
|
||||||
|
|
||||||
There may be some features `configure' cannot figure out automatically,
|
|
||||||
but needs to determine by the type of machine the package will run on.
|
|
||||||
Usually, assuming the package is built to be run on the _same_
|
|
||||||
architectures, `configure' can figure that out, but if it prints a
|
|
||||||
message saying it cannot guess the machine type, give it the
|
|
||||||
`--build=TYPE' option. TYPE can either be a short name for the system
|
|
||||||
type, such as `sun4', or a canonical name which has the form:
|
|
||||||
|
|
||||||
CPU-COMPANY-SYSTEM
|
|
||||||
|
|
||||||
where SYSTEM can have one of these forms:
|
|
||||||
|
|
||||||
OS KERNEL-OS
|
|
||||||
|
|
||||||
See the file `config.sub' for the possible values of each field. If
|
|
||||||
`config.sub' isn't included in this package, then this package doesn't
|
|
||||||
need to know the machine type.
|
|
||||||
|
|
||||||
If you are _building_ compiler tools for cross-compiling, you should
|
|
||||||
use the option `--target=TYPE' to select the type of system they will
|
|
||||||
produce code for.
|
|
||||||
|
|
||||||
If you want to _use_ a cross compiler, that generates code for a
|
|
||||||
platform different from the build platform, you should specify the
|
|
||||||
"host" platform (i.e., that on which the generated programs will
|
|
||||||
eventually be run) with `--host=TYPE'.
|
|
||||||
|
|
||||||
Sharing Defaults
|
|
||||||
================
|
|
||||||
|
|
||||||
If you want to set default values for `configure' scripts to share, you
|
|
||||||
can create a site shell script called `config.site' that gives default
|
|
||||||
values for variables like `CC', `cache_file', and `prefix'.
|
|
||||||
`configure' looks for `PREFIX/share/config.site' if it exists, then
|
|
||||||
`PREFIX/etc/config.site' if it exists. Or, you can set the
|
|
||||||
`CONFIG_SITE' environment variable to the location of the site script.
|
|
||||||
A warning: not all `configure' scripts look for a site script.
|
|
||||||
|
|
||||||
Defining Variables
|
|
||||||
==================
|
|
||||||
|
|
||||||
Variables not defined in a site shell script can be set in the
|
|
||||||
environment passed to `configure'. However, some packages may run
|
|
||||||
configure again during the build, and the customized values of these
|
|
||||||
variables may be lost. In order to avoid this problem, you should set
|
|
||||||
them in the `configure' command line, using `VAR=value'. For example:
|
|
||||||
|
|
||||||
./configure CC=/usr/local2/bin/gcc
|
|
||||||
|
|
||||||
causes the specified `gcc' to be used as the C compiler (unless it is
|
|
||||||
overridden in the site shell script).
|
|
||||||
|
|
||||||
Unfortunately, this technique does not work for `CONFIG_SHELL' due to
|
|
||||||
an Autoconf bug. Until the bug is fixed you can use this workaround:
|
|
||||||
|
|
||||||
CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
|
|
||||||
|
|
||||||
`configure' Invocation
|
|
||||||
======================
|
|
||||||
|
|
||||||
`configure' recognizes the following options to control how it operates.
|
|
||||||
|
|
||||||
`--help'
|
|
||||||
`-h'
|
|
||||||
Print a summary of the options to `configure', and exit.
|
|
||||||
|
|
||||||
`--version'
|
|
||||||
`-V'
|
|
||||||
Print the version of Autoconf used to generate the `configure'
|
|
||||||
script, and exit.
|
|
||||||
|
|
||||||
`--cache-file=FILE'
|
|
||||||
Enable the cache: use and save the results of the tests in FILE,
|
|
||||||
traditionally `config.cache'. FILE defaults to `/dev/null' to
|
|
||||||
disable caching.
|
|
||||||
|
|
||||||
`--config-cache'
|
|
||||||
`-C'
|
|
||||||
Alias for `--cache-file=config.cache'.
|
|
||||||
|
|
||||||
`--quiet'
|
|
||||||
`--silent'
|
|
||||||
`-q'
|
|
||||||
Do not print messages saying which checks are being made. To
|
|
||||||
suppress all normal output, redirect it to `/dev/null' (any error
|
|
||||||
messages will still be shown).
|
|
||||||
|
|
||||||
`--srcdir=DIR'
|
|
||||||
Look for the package's source code in directory DIR. Usually
|
|
||||||
`configure' can determine that directory automatically.
|
|
||||||
|
|
||||||
`configure' also accepts some other, not widely useful, options. Run
|
|
||||||
`configure --help' for more details.
|
|
||||||
|
|
||||||
|
The "meson configure" command will give you a list of available
|
||||||
|
command-line options.
|
||||||
|
|||||||
25
Makefile.am
25
Makefile.am
@@ -1,25 +0,0 @@
|
|||||||
ACLOCAL_AMFLAGS = -I m4
|
|
||||||
EXTRA_DIST = THANKS TODO HACKING libfprint.pc.in
|
|
||||||
DISTCLEANFILES = ChangeLog libfprint.pc
|
|
||||||
|
|
||||||
SUBDIRS = libfprint doc
|
|
||||||
|
|
||||||
if BUILD_EXAMPLES
|
|
||||||
SUBDIRS += examples
|
|
||||||
endif
|
|
||||||
|
|
||||||
DIST_SUBDIRS = libfprint doc examples
|
|
||||||
|
|
||||||
DISTCHECK_CONFIGURE_FLAGS = --with-drivers=all --enable-examples-build --enable-x11-examples-build --with-udev-rules-dir='$${libdir}/udev/rules.d-distcheck'
|
|
||||||
|
|
||||||
pkgconfigdir=$(libdir)/pkgconfig
|
|
||||||
pkgconfig_DATA=libfprint.pc
|
|
||||||
|
|
||||||
.PHONY: ChangeLog dist-up
|
|
||||||
ChangeLog:
|
|
||||||
git --git-dir $(top_srcdir)/.git log > ChangeLog || touch ChangeLog
|
|
||||||
|
|
||||||
dist-hook: ChangeLog
|
|
||||||
|
|
||||||
dist-up: dist
|
|
||||||
rsync $(distdir).tar.bz2 frs.sourceforge.net:uploads/
|
|
||||||
106
NEWS
106
NEWS
@@ -1,6 +1,112 @@
|
|||||||
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-08-08: v1.0 release
|
||||||
|
* Library:
|
||||||
|
- Add guards to the public API and require GLib 2.50
|
||||||
|
- Deprecate print storage API
|
||||||
|
- Better documentation for fp_discover_devs()
|
||||||
|
- Remove unused internal fpi_timeout_cancel_for_dev()
|
||||||
|
- Remove state from fp_img_driver activate handler
|
||||||
|
- Bug fixes related to restarting a failed verification immediately
|
||||||
|
|
||||||
|
* Drivers:
|
||||||
|
- The Elan driver received a lot of bug fixes including a fix for a
|
||||||
|
hang when verifying prints with fprintd, quirks for some devices,
|
||||||
|
a memory leak fix and support for 04f3:0c42
|
||||||
|
- Fix a probable crash in all the AES drivers
|
||||||
|
- Add support for Lenovo Preferred Pro Keyboard (KUF1256) to vfs5011
|
||||||
|
- Prevent hang during enroll process in etes603 driver
|
||||||
|
- Fix possible integer overflow in uru4000
|
||||||
|
- Work-around SELinux AVC warnings when uru4000 driver starts
|
||||||
|
- Remove long-unmaintained and broken fdu2000 driver
|
||||||
|
|
||||||
|
* Tools/Examples:
|
||||||
|
- Fix examples not working due to an overly strict check
|
||||||
|
- Fix crash in GTK demo when there's no supported devices
|
||||||
|
- Disable GTK demo until we have a USB Flatpak portal
|
||||||
|
- Remove sleep() in enroll example which caused a crash in some drivers
|
||||||
|
- Add a simple storage implementation example
|
||||||
|
|
||||||
|
2018-12-14: v0.99.0 release
|
||||||
|
* Library:
|
||||||
|
- All the internal API for device driver writers is now covered by the
|
||||||
|
documentation and has been enhanced to make it easier to write drivers
|
||||||
|
- Update internal NBIS fingerprint data processing library to one that's
|
||||||
|
nearly 10 years newer
|
||||||
|
- Re-add accessor for minutia coordinates which was used in the very
|
||||||
|
old fprint_demo program, but also by our new GTK+ test program (see below)
|
||||||
|
- Fix a crash when too many minutiae were detected in a capture
|
||||||
|
|
||||||
|
* Drivers:
|
||||||
|
- Support more devices in the Elan driver, stability improvements
|
||||||
|
|
||||||
|
* Tools:
|
||||||
|
- Add a test GTK+ application that will eventually be used for testing
|
||||||
|
drivers without modifying the OS installed version. Note that this
|
||||||
|
application currently requires manually changing permissions of USB
|
||||||
|
devices, this will be fixed when the infrastructure exists to access
|
||||||
|
those devices without additional permissions, as a normal user.
|
||||||
|
|
||||||
|
2018-07-15: v0.8.2 release
|
||||||
|
* Drivers:
|
||||||
|
- Add USB ID for TNP Nano USB Fingerprint Reader
|
||||||
|
- Fix UPEKTS enrollment never finishing on some devices
|
||||||
|
|
||||||
|
* Library:
|
||||||
|
- Fix fp_get_pollfds() retval type, a small ABI change
|
||||||
|
- Downgrade fatal errors to run-time warnings, as a number of drivers
|
||||||
|
used to throw silent errors and we made them fatal. Those will now
|
||||||
|
be visible warnings, hopefully helping with fixing them.
|
||||||
|
|
||||||
|
2018-06-12: v0.8.1 release
|
||||||
|
- Brown paperbag release to install the udev rules file in the correct
|
||||||
|
directory if the udev pkg-config file doesn't have a trailing slash
|
||||||
|
|
||||||
|
2018-06-12: v0.8.0 release
|
||||||
|
- Port to meson as the build system
|
||||||
|
- Port documentation to gtk-doc
|
||||||
|
|
||||||
|
* Drivers:
|
||||||
|
- Add Elan driver
|
||||||
|
- Increase threshold to detect encryption on URU4000 devices
|
||||||
|
- Remove already replaced UPEKE2 driver
|
||||||
|
- Fix possible crash caused by vfs5011 when no lines were captured
|
||||||
|
|
||||||
|
* Library:
|
||||||
|
- Fix a number of memory and file descriptor leaks and warnings
|
||||||
|
- Make NSS (and URU4000) driver optional
|
||||||
|
- Fix assembling of frames for non-reverse and non reverse stripes
|
||||||
|
- Split internal private header to clarify drivers API
|
||||||
|
- Simplify logging system, now all the builds can be used to output
|
||||||
|
debug information
|
||||||
|
- Mark fp_dscv_print functions as deprecated
|
||||||
|
|
||||||
|
* Udev rules:
|
||||||
|
- Add some unsupported devices to the whitelist
|
||||||
|
|
||||||
|
2017-05-14: v0.7.0 release
|
||||||
|
* Drivers:
|
||||||
|
- Add VFS0050 driver
|
||||||
|
- Fix possible crash in AES3500 and AES4000
|
||||||
|
- Fix broken enrollment in VFS101
|
||||||
|
- Better verification with small sensor scanners
|
||||||
|
- Plenty of fixes in VFS5011
|
||||||
|
- Fix memory corruption in AES1610
|
||||||
|
- Improve calibration settings for AES1610
|
||||||
|
- Improve image assembling in upeksonly driver
|
||||||
|
- Autodetect whether image is encrypted in uru4k
|
||||||
|
|
||||||
|
* Library:
|
||||||
|
- NBIS: Remove false minutia at the edge of partial image
|
||||||
|
- Introduce routines to assemble image from lines (used in VFS5011 and upeksonly)
|
||||||
|
- Fix a bug that can cause driver state machine to enter into endless loop.
|
||||||
|
|
||||||
|
* Udev rules:
|
||||||
|
- Add driver name to the USB properties
|
||||||
|
|
||||||
|
* Plenty of build fixes
|
||||||
|
|
||||||
2015-02-03: v0.6.0 release
|
2015-02-03: v0.6.0 release
|
||||||
|
|
||||||
* Drivers:
|
* Drivers:
|
||||||
|
|||||||
16
README
16
README
@@ -2,7 +2,7 @@ libfprint
|
|||||||
=========
|
=========
|
||||||
|
|
||||||
libfprint is part of the fprint project:
|
libfprint is part of the fprint project:
|
||||||
http://www.reactivated.net/fprint
|
https://fprint.freedesktop.org/
|
||||||
|
|
||||||
libfprint was originally developed as part of an academic project at the
|
libfprint was originally developed as part of an academic project at the
|
||||||
University of Manchester with the aim of hiding differences between different
|
University of Manchester with the aim of hiding differences between different
|
||||||
@@ -22,7 +22,7 @@ university computers and the project is not hosted at the university either.
|
|||||||
|
|
||||||
For more information on libfprint, supported devices, API documentation, etc.,
|
For more information on libfprint, supported devices, API documentation, etc.,
|
||||||
see the homepage:
|
see the homepage:
|
||||||
http://www.reactivated.net/fprint/Libfprint
|
https://fprint.freedesktop.org/
|
||||||
|
|
||||||
libfprint is licensed under the GNU LGPL version 2.1. See the COPYING file
|
libfprint is licensed under the GNU LGPL version 2.1. See the COPYING file
|
||||||
for the license text.
|
for the license text.
|
||||||
@@ -37,5 +37,15 @@ libfprint includes code from NIST's NBIS software distribution:
|
|||||||
http://fingerprint.nist.gov/NBIS/index.html
|
http://fingerprint.nist.gov/NBIS/index.html
|
||||||
We include bozorth3 from the US export controlled distribution. We have
|
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 http://reactivated.net/fprint/wiki/US_export_control
|
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/
|
||||||
|
|||||||
10
autogen.sh
10
autogen.sh
@@ -1,10 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
libtoolize --copy --force || exit 1
|
|
||||||
aclocal || exit 1
|
|
||||||
autoheader || exit 1
|
|
||||||
autoconf || exit 1
|
|
||||||
automake -a -c || exit 1
|
|
||||||
if test -z "$NOCONFIGURE"; then
|
|
||||||
exec ./configure --enable-maintainer-mode --enable-examples-build \
|
|
||||||
--enable-x11-examples-build --enable-debug-log $*
|
|
||||||
fi
|
|
||||||
3
code-of-conduct.md
Normal file
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/
|
||||||
417
configure.ac
417
configure.ac
@@ -1,417 +0,0 @@
|
|||||||
AC_INIT([libfprint], [0.6.0])
|
|
||||||
AM_INIT_AUTOMAKE([1.11 no-dist-gzip dist-xz check-news subdir-objects])
|
|
||||||
AC_CONFIG_MACRO_DIR([m4])
|
|
||||||
AC_CONFIG_SRCDIR([libfprint/core.c])
|
|
||||||
AC_CONFIG_HEADERS([config.h])
|
|
||||||
|
|
||||||
# Enable silent build when available (Automake 1.11)
|
|
||||||
m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
|
|
||||||
|
|
||||||
AC_PREREQ([2.50])
|
|
||||||
AC_PROG_CC
|
|
||||||
AC_PROG_LIBTOOL
|
|
||||||
AC_C_INLINE
|
|
||||||
AM_PROG_CC_C_O
|
|
||||||
AC_PROG_CXX
|
|
||||||
AC_DEFINE([_GNU_SOURCE], [], [Use GNU extensions])
|
|
||||||
|
|
||||||
# Library versioning
|
|
||||||
lt_major="0"
|
|
||||||
lt_revision="0"
|
|
||||||
lt_age="0"
|
|
||||||
AC_SUBST(lt_major)
|
|
||||||
AC_SUBST(lt_revision)
|
|
||||||
AC_SUBST(lt_age)
|
|
||||||
|
|
||||||
all_drivers="upekts upektc upeksonly vcom5s uru4000 fdu2000 aes1610 aes1660 aes2501 aes2550 aes2660 aes3500 aes4000 vfs101 vfs301 vfs5011 upektc_img etes603"
|
|
||||||
|
|
||||||
require_imaging='no'
|
|
||||||
require_aeslib='no'
|
|
||||||
require_aesX660='no'
|
|
||||||
require_aes3k='no'
|
|
||||||
enable_upeke2='no'
|
|
||||||
enable_upekts='no'
|
|
||||||
enable_upektc='no'
|
|
||||||
enable_upeksonly='no'
|
|
||||||
enable_vcom5s='no'
|
|
||||||
enable_uru4000='no'
|
|
||||||
enable_fdu2000='no'
|
|
||||||
enable_aes1610='no'
|
|
||||||
enable_aes1660='no'
|
|
||||||
enable_aes2501='no'
|
|
||||||
enable_aes2550='no'
|
|
||||||
enable_aes2660='no'
|
|
||||||
enable_aes3500='no'
|
|
||||||
enable_aes4000='no'
|
|
||||||
enable_vfs101='no'
|
|
||||||
enable_vfs301='no'
|
|
||||||
enable_vfs5011='no'
|
|
||||||
enable_upektc_img='no'
|
|
||||||
enable_etes603='no'
|
|
||||||
|
|
||||||
AC_ARG_WITH([drivers],[AS_HELP_STRING([--with-drivers],
|
|
||||||
[List of drivers to enable])],
|
|
||||||
[drivers="$withval"],
|
|
||||||
[drivers="$all_drivers"])
|
|
||||||
|
|
||||||
if test "x$drivers" = "xall" ; then
|
|
||||||
drivers=$all_drivers
|
|
||||||
fi
|
|
||||||
|
|
||||||
for driver in `echo ${drivers} | sed -e 's/,/ /g' -e 's/,$//g'`; do
|
|
||||||
case ${driver} in
|
|
||||||
upekts)
|
|
||||||
AC_DEFINE([ENABLE_UPEKTS], [], [Build UPEK TouchStrip driver])
|
|
||||||
enable_upekts="yes"
|
|
||||||
;;
|
|
||||||
upeke2)
|
|
||||||
AC_DEFINE([ENABLE_UPEKE2], [], [Build UPEK Eikon 2])
|
|
||||||
enable_upeke2="yes"
|
|
||||||
;;
|
|
||||||
upektc)
|
|
||||||
AC_DEFINE([ENABLE_UPEKTC], [], [Build UPEK TouchChip driver])
|
|
||||||
enable_upektc="yes"
|
|
||||||
;;
|
|
||||||
upeksonly)
|
|
||||||
AC_DEFINE([ENABLE_UPEKSONLY], [], [Build UPEK TouchStrip sensor-only driver])
|
|
||||||
enable_upeksonly="yes"
|
|
||||||
;;
|
|
||||||
uru4000)
|
|
||||||
AC_DEFINE([ENABLE_URU4000], [], [Build Digital Persona U.are.U 4000 driver])
|
|
||||||
enable_uru4000="yes"
|
|
||||||
;;
|
|
||||||
fdu2000)
|
|
||||||
AC_DEFINE([ENABLE_FDU2000], [], [Build Secugen FDU 2000 driver])
|
|
||||||
enable_fdu2000="no"
|
|
||||||
# Driver not ported
|
|
||||||
;;
|
|
||||||
vcom5s)
|
|
||||||
AC_DEFINE([ENABLE_VCOM5S], [], [Build Veridicom 5thSense driver])
|
|
||||||
enable_vcom5s="yes"
|
|
||||||
;;
|
|
||||||
aes2501)
|
|
||||||
AC_DEFINE([ENABLE_AES2501], [], [Build AuthenTec AES2501 driver])
|
|
||||||
require_aeslib="yes"
|
|
||||||
enable_aes2501="yes"
|
|
||||||
;;
|
|
||||||
aes2550)
|
|
||||||
AC_DEFINE([ENABLE_AES2550], [], [Build AuthenTec AES2550/AES2810 driver])
|
|
||||||
require_aeslib="yes"
|
|
||||||
enable_aes2550="yes"
|
|
||||||
;;
|
|
||||||
aes1610)
|
|
||||||
AC_DEFINE([ENABLE_AES1610], [], [Build AuthenTec AES1610 driver])
|
|
||||||
require_aeslib="yes"
|
|
||||||
enable_aes1610="yes"
|
|
||||||
;;
|
|
||||||
aes1660)
|
|
||||||
AC_DEFINE([ENABLE_AES1660], [], [Build AuthenTec AES1660 driver])
|
|
||||||
require_aeslib="yes"
|
|
||||||
require_aesX660="yes"
|
|
||||||
enable_aes1660="yes"
|
|
||||||
;;
|
|
||||||
aes2660)
|
|
||||||
AC_DEFINE([ENABLE_AES2660], [], [Build AuthenTec AES1660 driver])
|
|
||||||
require_aeslib="yes"
|
|
||||||
require_aesX660="yes"
|
|
||||||
enable_aes2660="yes"
|
|
||||||
;;
|
|
||||||
aes3500)
|
|
||||||
AC_DEFINE([ENABLE_AES3500], [], [Build AuthenTec AES3500 driver])
|
|
||||||
require_aeslib="yes"
|
|
||||||
require_imaging="yes"
|
|
||||||
require_aes3k="yes"
|
|
||||||
enable_aes3500="yes"
|
|
||||||
;;
|
|
||||||
aes4000)
|
|
||||||
AC_DEFINE([ENABLE_AES4000], [], [Build AuthenTec AES4000 driver])
|
|
||||||
require_aeslib="yes"
|
|
||||||
require_imaging="yes"
|
|
||||||
require_aes3k="yes"
|
|
||||||
enable_aes4000="yes"
|
|
||||||
;;
|
|
||||||
vfs101)
|
|
||||||
AC_DEFINE([ENABLE_VFS101], [], [Build Validity VFS101 driver])
|
|
||||||
enable_vfs101="yes"
|
|
||||||
;;
|
|
||||||
vfs301)
|
|
||||||
AC_DEFINE([ENABLE_VFS301], [], [Build Validity VFS301/VFS300 driver])
|
|
||||||
enable_vfs301="yes"
|
|
||||||
;;
|
|
||||||
vfs5011)
|
|
||||||
AC_DEFINE([ENABLE_VFS5011], [], [Build Validity VFS5011 driver])
|
|
||||||
enable_vfs5011="yes"
|
|
||||||
;;
|
|
||||||
upektc_img)
|
|
||||||
AC_DEFINE([ENABLE_UPEKTC_IMG], [], [Build Upek TouchChip Fingerprint Coprocessor driver])
|
|
||||||
enable_upektc_img="yes"
|
|
||||||
;;
|
|
||||||
etes603)
|
|
||||||
AC_DEFINE([ENABLE_ETES603], [], [Build EgisTec ES603 driver])
|
|
||||||
enable_etes603="yes"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
AM_CONDITIONAL([ENABLE_UPEKTS], [test "$enable_upekts" = "yes"])
|
|
||||||
AM_CONDITIONAL([ENABLE_UPEKE2], [test "$enable_upeke2" = "yes"])
|
|
||||||
AM_CONDITIONAL([ENABLE_UPEKTC], [test "$enable_upektc" = "yes"])
|
|
||||||
AM_CONDITIONAL([ENABLE_UPEKSONLY], [test "$enable_upeksonly" = "yes"])
|
|
||||||
AM_CONDITIONAL([ENABLE_VCOM5S], [test "$enable_vcom5s" = "yes"])
|
|
||||||
AM_CONDITIONAL([ENABLE_URU4000], [test "$enable_uru4000" = "yes"])
|
|
||||||
AM_CONDITIONAL([ENABLE_FDU2000], [test "$enable_fdu2000" = "yes"])
|
|
||||||
AM_CONDITIONAL([ENABLE_AES1610], [test "$enable_aes1610" = "yes"])
|
|
||||||
AM_CONDITIONAL([ENABLE_AES1660], [test "$enable_aes1660" = "yes"])
|
|
||||||
AM_CONDITIONAL([ENABLE_AES2501], [test "$enable_aes2501" = "yes"])
|
|
||||||
AM_CONDITIONAL([ENABLE_AES2550], [test "$enable_aes2550" = "yes"])
|
|
||||||
AM_CONDITIONAL([ENABLE_AES2660], [test "$enable_aes2660" = "yes"])
|
|
||||||
AM_CONDITIONAL([ENABLE_AES3500], [test "$enable_aes3500" = "yes"])
|
|
||||||
AM_CONDITIONAL([ENABLE_AES4000], [test "$enable_aes4000" = "yes"])
|
|
||||||
AM_CONDITIONAL([REQUIRE_AESLIB], [test "$require_aeslib" = "yes"])
|
|
||||||
AM_CONDITIONAL([REQUIRE_AESX660], [test "$require_aesX660" = "yes"])
|
|
||||||
AM_CONDITIONAL([REQUIRE_AES3K], [test "$require_aes3k" = "yes"])
|
|
||||||
AM_CONDITIONAL([ENABLE_VFS101], [test "$enable_vfs101" = "yes"])
|
|
||||||
AM_CONDITIONAL([ENABLE_VFS301], [test "$enable_vfs301" = "yes"])
|
|
||||||
AM_CONDITIONAL([ENABLE_VFS5011], [test "$enable_vfs5011" = "yes"])
|
|
||||||
AM_CONDITIONAL([ENABLE_UPEKTC_IMG], [test "$enable_upektc_img" = "yes"])
|
|
||||||
AM_CONDITIONAL([ENABLE_ETES603], [test "$enable_etes603" = "yes"])
|
|
||||||
|
|
||||||
|
|
||||||
PKG_CHECK_MODULES(LIBUSB, [libusb-1.0 >= 0.9.1])
|
|
||||||
AC_SUBST(LIBUSB_CFLAGS)
|
|
||||||
AC_SUBST(LIBUSB_LIBS)
|
|
||||||
|
|
||||||
# check for OpenSSL's libcrypto
|
|
||||||
PKG_CHECK_MODULES(CRYPTO, nss)
|
|
||||||
AC_SUBST(CRYPTO_CFLAGS)
|
|
||||||
AC_SUBST(CRYPTO_LIBS)
|
|
||||||
|
|
||||||
PKG_CHECK_MODULES(GLIB, [glib-2.0 >= 2.28])
|
|
||||||
AC_SUBST(GLIB_CFLAGS)
|
|
||||||
AC_SUBST(GLIB_LIBS)
|
|
||||||
|
|
||||||
pixman_found=no
|
|
||||||
|
|
||||||
AC_ARG_ENABLE(udev-rules,
|
|
||||||
AC_HELP_STRING([--enable-udev-rules],[Update the udev rules]),
|
|
||||||
[case "${enableval}" in
|
|
||||||
yes) ENABLE_UDEV_RULES=yes ;;
|
|
||||||
no) ENABLE_UDEV_RULES=no ;;
|
|
||||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-udev-rules) ;;
|
|
||||||
esac],
|
|
||||||
[ENABLE_UDEV_RULES=yes]) dnl Default value
|
|
||||||
AM_CONDITIONAL(ENABLE_UDEV_RULES, test x$ENABLE_UDEV_RULES = "xyes")
|
|
||||||
|
|
||||||
if test $ENABLE_UDEV_RULES = no && test -d .git/ ; then
|
|
||||||
AC_MSG_ERROR(--disable-udev-rules can only be used when building from tarballs)
|
|
||||||
fi
|
|
||||||
|
|
||||||
AC_ARG_WITH(udev-rules-dir,
|
|
||||||
AS_HELP_STRING([--with-udev-rules-dir=DIR],[Installation path for udev rules @<:@auto@:>@]),
|
|
||||||
[ac_with_udev_rules_dir=$withval],
|
|
||||||
[ac_with_udev_rules_dir=""])
|
|
||||||
|
|
||||||
if test "${ac_with_udev_rules_dir}" = ""; then
|
|
||||||
ac_with_udev_rules_dir=`$PKG_CONFIG --variable=udevdir udev`/rules.d
|
|
||||||
fi
|
|
||||||
AC_MSG_NOTICE([installing udev rules in ${ac_with_udev_rules_dir}])
|
|
||||||
AC_SUBST([udev_rulesdir],[${ac_with_udev_rules_dir}])
|
|
||||||
|
|
||||||
if test "$require_imaging" = "yes"; then
|
|
||||||
PKG_CHECK_MODULES(IMAGING, pixman-1, [pixman_found=yes], [pixman_found=no])
|
|
||||||
if test "$pixman_found" != "yes"; then
|
|
||||||
AC_MSG_ERROR([pixman is required for imaging support])
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
AM_CONDITIONAL([REQUIRE_PIXMAN], [test "$pixman_found" = "yes"])
|
|
||||||
AC_SUBST(IMAGING_CFLAGS)
|
|
||||||
AC_SUBST(IMAGING_LIBS)
|
|
||||||
|
|
||||||
# Examples build
|
|
||||||
AC_ARG_ENABLE([examples-build], [AS_HELP_STRING([--enable-examples-build],
|
|
||||||
[build example applications (default n)])],
|
|
||||||
[build_examples=$enableval],
|
|
||||||
[build_examples='no'])
|
|
||||||
AM_CONDITIONAL([BUILD_EXAMPLES], [test "x$build_examples" != "xno"])
|
|
||||||
|
|
||||||
# Examples build
|
|
||||||
AC_ARG_ENABLE([x11-examples-build], [AS_HELP_STRING([--enable-x11-examples-build],
|
|
||||||
[build X11 example applications (default n)])],
|
|
||||||
[build_x11_examples=$enableval],
|
|
||||||
[build_x11_examples='no'])
|
|
||||||
AM_CONDITIONAL([BUILD_X11_EXAMPLES], [test "x$build_x11_examples" != "xno"])
|
|
||||||
|
|
||||||
|
|
||||||
if test "x$build_x11_examples" != "xno"; then
|
|
||||||
# check for Xv extensions
|
|
||||||
# imported from Coriander
|
|
||||||
AC_DEFUN([AC_CHECK_XV],[
|
|
||||||
AC_SUBST(XV_CFLAGS)
|
|
||||||
AC_SUBST(XV_LIBS)
|
|
||||||
AC_MSG_CHECKING(for Xv extensions)
|
|
||||||
AC_TRY_COMPILE([
|
|
||||||
#include <X11/Xlib.h>
|
|
||||||
#include <X11/extensions/Xvlib.h>],[
|
|
||||||
int main(void) { (void) XvGetPortAttribute(0, 0, 0, 0); return 0; }
|
|
||||||
],xv=yes,xv=no);
|
|
||||||
AC_MSG_RESULT($xv)
|
|
||||||
if test x$xv = xyes; then
|
|
||||||
XV_LIBS="-lXv -lXext"
|
|
||||||
XV_CFLAGS=""
|
|
||||||
AC_DEFINE(HAVE_XV,1,[defined if XV video overlay is available])
|
|
||||||
else
|
|
||||||
AC_MSG_ERROR([XV is required for X11 examples])
|
|
||||||
fi
|
|
||||||
])
|
|
||||||
AC_CHECK_XV
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Message logging
|
|
||||||
AC_ARG_ENABLE([log], [AS_HELP_STRING([--disable-log], [disable all logging])],
|
|
||||||
[log_enabled=$enableval],
|
|
||||||
[log_enabled='yes'])
|
|
||||||
if test "x$log_enabled" != "xno"; then
|
|
||||||
AC_DEFINE([ENABLE_LOGGING], 1, [Message logging])
|
|
||||||
fi
|
|
||||||
|
|
||||||
AC_ARG_ENABLE([debug-log], [AS_HELP_STRING([--enable-debug-log],
|
|
||||||
[enable debug logging (default n)])],
|
|
||||||
[debug_log_enabled=$enableval],
|
|
||||||
[debug_log_enabled='no'])
|
|
||||||
if test "x$debug_log_enabled" != "xno"; then
|
|
||||||
AC_DEFINE([ENABLE_DEBUG_LOGGING], 1, [Debug message logging])
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Restore gnu89 inline semantics on gcc 4.3 and newer
|
|
||||||
saved_cflags="$CFLAGS"
|
|
||||||
CFLAGS="$CFLAGS -fgnu89-inline"
|
|
||||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[]])], inline_cflags="-fgnu89-inline", inline_cflags="")
|
|
||||||
CFLAGS="$saved_cflags"
|
|
||||||
|
|
||||||
AC_DEFINE([API_EXPORTED], [__attribute__((visibility("default")))], [Default visibility])
|
|
||||||
AM_CFLAGS="-std=gnu99 $inline_cflags -Wall -Wundef -Wunused -Wstrict-prototypes -Werror-implicit-function-declaration -Wno-pointer-sign -Wshadow"
|
|
||||||
AC_SUBST(AM_CFLAGS)
|
|
||||||
|
|
||||||
if test "$require_imaging" = "yes"; then
|
|
||||||
if test x$pixman_found != no; then
|
|
||||||
AC_MSG_NOTICE([** Using pixman for imaging])
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
AC_MSG_NOTICE([ Imaging support disabled])
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test x$enable_upekts != xno ; then
|
|
||||||
AC_MSG_NOTICE([** upekts driver enabled])
|
|
||||||
else
|
|
||||||
AC_MSG_NOTICE([ upekts driver disabled])
|
|
||||||
fi
|
|
||||||
if test x$enable_upeke2 != xno ; then
|
|
||||||
AC_MSG_NOTICE([** upeke2 driver enabled])
|
|
||||||
else
|
|
||||||
AC_MSG_NOTICE([ upeke2 driver disabled])
|
|
||||||
fi
|
|
||||||
if test x$enable_upektc != xno ; then
|
|
||||||
AC_MSG_NOTICE([** upektc driver enabled])
|
|
||||||
else
|
|
||||||
AC_MSG_NOTICE([ upektc driver disabled])
|
|
||||||
fi
|
|
||||||
if test x$enable_upeksonly != xno ; then
|
|
||||||
AC_MSG_NOTICE([** upeksonly driver enabled])
|
|
||||||
else
|
|
||||||
AC_MSG_NOTICE([ upeksonly driver disabled])
|
|
||||||
fi
|
|
||||||
if test x$enable_vcom5s != xno ; then
|
|
||||||
AC_MSG_NOTICE([** vcom5s driver enabled])
|
|
||||||
else
|
|
||||||
AC_MSG_NOTICE([ vcom5s driver disabled])
|
|
||||||
fi
|
|
||||||
if test x$enable_uru4000 != xno ; then
|
|
||||||
AC_MSG_NOTICE([** uru4000 driver enabled])
|
|
||||||
else
|
|
||||||
AC_MSG_NOTICE([ uru4000 driver disabled])
|
|
||||||
fi
|
|
||||||
if test x$enable_fdu2000 != xno ; then
|
|
||||||
AC_MSG_NOTICE([** fdu2000 driver enabled])
|
|
||||||
else
|
|
||||||
AC_MSG_NOTICE([ fdu2000 driver disabled])
|
|
||||||
fi
|
|
||||||
if test x$enable_aes1610 != xno ; then
|
|
||||||
AC_MSG_NOTICE([** aes1610 driver enabled])
|
|
||||||
else
|
|
||||||
AC_MSG_NOTICE([ aes1610 driver disabled])
|
|
||||||
fi
|
|
||||||
if test x$enable_aes1660 != xno ; then
|
|
||||||
AC_MSG_NOTICE([** aes1660 driver enabled])
|
|
||||||
else
|
|
||||||
AC_MSG_NOTICE([ aes1660 driver disabled])
|
|
||||||
fi
|
|
||||||
if test x$enable_aes2501 != xno ; then
|
|
||||||
AC_MSG_NOTICE([** aes2501 driver enabled])
|
|
||||||
else
|
|
||||||
AC_MSG_NOTICE([ aes2501 driver disabled])
|
|
||||||
fi
|
|
||||||
if test x$enable_aes2550 != xno ; then
|
|
||||||
AC_MSG_NOTICE([** aes2550/aes2810 driver enabled])
|
|
||||||
else
|
|
||||||
AC_MSG_NOTICE([ aes2550/aes2810 driver disabled])
|
|
||||||
fi
|
|
||||||
if test x$enable_aes2660 != xno ; then
|
|
||||||
AC_MSG_NOTICE([** aes2660 driver enabled])
|
|
||||||
else
|
|
||||||
AC_MSG_NOTICE([ aes2660 driver disabled])
|
|
||||||
fi
|
|
||||||
if test x$enable_aes3500 != xno ; then
|
|
||||||
AC_MSG_NOTICE([** aes3500 driver enabled])
|
|
||||||
else
|
|
||||||
AC_MSG_NOTICE([ aes3500 driver disabled])
|
|
||||||
fi
|
|
||||||
if test x$enable_aes4000 != xno ; then
|
|
||||||
AC_MSG_NOTICE([** aes4000 driver enabled])
|
|
||||||
else
|
|
||||||
AC_MSG_NOTICE([ aes4000 driver disabled])
|
|
||||||
fi
|
|
||||||
if test x$enable_vfs101 != xno ; then
|
|
||||||
AC_MSG_NOTICE([** vfs101 driver enabled])
|
|
||||||
else
|
|
||||||
AC_MSG_NOTICE([ vfs101 driver disabled])
|
|
||||||
fi
|
|
||||||
if test x$enable_vfs301 != xno ; then
|
|
||||||
AC_MSG_NOTICE([** vfs301 driver enabled])
|
|
||||||
else
|
|
||||||
AC_MSG_NOTICE([ vfs301 driver disabled])
|
|
||||||
fi
|
|
||||||
if test x$enable_vfs5011 != xno ; then
|
|
||||||
AC_MSG_NOTICE([** vfs5011 driver enabled])
|
|
||||||
else
|
|
||||||
AC_MSG_NOTICE([ vfs5011 driver disabled])
|
|
||||||
fi
|
|
||||||
if test x$enable_upektc_img != xno ; then
|
|
||||||
AC_MSG_NOTICE([** upektc_img driver enabled])
|
|
||||||
else
|
|
||||||
AC_MSG_NOTICE([ upektc_img driver disabled])
|
|
||||||
fi
|
|
||||||
if test x$enable_etes603 != xno ; then
|
|
||||||
AC_MSG_NOTICE([** etes603 driver enabled])
|
|
||||||
else
|
|
||||||
AC_MSG_NOTICE([ etes603 driver disabled])
|
|
||||||
fi
|
|
||||||
if test x$require_aeslib != xno ; then
|
|
||||||
AC_MSG_NOTICE([** aeslib helper functions enabled])
|
|
||||||
else
|
|
||||||
AC_MSG_NOTICE([ aeslib helper functions disabled])
|
|
||||||
fi
|
|
||||||
if test x$require_aesX660 != xno ; then
|
|
||||||
AC_MSG_NOTICE([** aesX660 common routines enabled])
|
|
||||||
else
|
|
||||||
AC_MSG_NOTICE([ aesX660 common routines disabled])
|
|
||||||
fi
|
|
||||||
if test x$require_aes3k != xno ; then
|
|
||||||
AC_MSG_NOTICE([** aes3k common routines enabled])
|
|
||||||
else
|
|
||||||
AC_MSG_NOTICE([ aes3k common routines disabled])
|
|
||||||
fi
|
|
||||||
|
|
||||||
AC_CONFIG_FILES([libfprint.pc] [Makefile] [libfprint/Makefile] [examples/Makefile] [doc/Makefile])
|
|
||||||
AC_OUTPUT
|
|
||||||
|
|
||||||
523
demo/gtk-libfprint-test.c
Normal file
523
demo/gtk-libfprint-test.c
Normal file
@@ -0,0 +1,523 @@
|
|||||||
|
/*
|
||||||
|
* 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>
|
||||||
|
|
||||||
|
#include "loop.h"
|
||||||
|
|
||||||
|
typedef GtkApplication LibfprintDemo;
|
||||||
|
typedef GtkApplicationClass LibfprintDemoClass;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
GtkApplicationWindow parent_instance;
|
||||||
|
|
||||||
|
GtkWidget *header_bar;
|
||||||
|
GtkWidget *mode_stack;
|
||||||
|
GtkWidget *capture_button;
|
||||||
|
GtkWidget *capture_image;
|
||||||
|
GtkWidget *spinner;
|
||||||
|
GtkWidget *instructions;
|
||||||
|
|
||||||
|
struct fp_dscv_dev *ddev;
|
||||||
|
struct fp_dev *dev;
|
||||||
|
|
||||||
|
struct fp_img *img;
|
||||||
|
ImageDisplayFlags img_flags;
|
||||||
|
} LibfprintDemoWindow;
|
||||||
|
|
||||||
|
typedef GtkApplicationWindowClass LibfprintDemoWindowClass;
|
||||||
|
|
||||||
|
G_DEFINE_TYPE (LibfprintDemoWindow, libfprint_demo_window, GTK_TYPE_APPLICATION_WINDOW)
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
EMPTY_MODE,
|
||||||
|
NOIMAGING_MODE,
|
||||||
|
CAPTURE_MODE,
|
||||||
|
SPINNER_MODE,
|
||||||
|
ERROR_MODE
|
||||||
|
} LibfprintDemoMode;
|
||||||
|
|
||||||
|
static void libfprint_demo_set_mode (LibfprintDemoWindow *win,
|
||||||
|
LibfprintDemoMode mode);
|
||||||
|
|
||||||
|
static void
|
||||||
|
pixbuf_destroy (guchar *pixels, gpointer data)
|
||||||
|
{
|
||||||
|
if (pixels == NULL)
|
||||||
|
return;
|
||||||
|
g_free (pixels);
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned char *
|
||||||
|
img_to_rgbdata (struct fp_img *img,
|
||||||
|
int width,
|
||||||
|
int height)
|
||||||
|
{
|
||||||
|
int size = width * height;
|
||||||
|
unsigned char *imgdata = fp_img_get_data (img);
|
||||||
|
unsigned char *rgbdata = g_malloc (size * 3);
|
||||||
|
size_t i;
|
||||||
|
size_t rgb_offset = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
unsigned char 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,
|
||||||
|
struct fp_minutia **minlist,
|
||||||
|
int nr_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 < nr_minutiae; i++) {
|
||||||
|
struct fp_minutia *min = minlist[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 (struct fp_img *img,
|
||||||
|
ImageDisplayFlags flags)
|
||||||
|
{
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
unsigned char *rgbdata;
|
||||||
|
|
||||||
|
width = fp_img_get_width (img);
|
||||||
|
height = fp_img_get_height (img);
|
||||||
|
|
||||||
|
if (flags & IMAGE_DISPLAY_BINARY) {
|
||||||
|
struct fp_img *binary;
|
||||||
|
binary = fp_img_binarize (img);
|
||||||
|
rgbdata = img_to_rgbdata (binary, width, height);
|
||||||
|
fp_img_free (binary);
|
||||||
|
} else {
|
||||||
|
rgbdata = img_to_rgbdata (img, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & IMAGE_DISPLAY_MINUTIAE) {
|
||||||
|
struct fp_minutia **minlist;
|
||||||
|
int nr_minutiae;
|
||||||
|
|
||||||
|
minlist = fp_img_get_minutiae (img, &nr_minutiae);
|
||||||
|
plot_minutiae (rgbdata, width, height, minlist, nr_minutiae);
|
||||||
|
}
|
||||||
|
|
||||||
|
return gdk_pixbuf_new_from_data (rgbdata, GDK_COLORSPACE_RGB,
|
||||||
|
FALSE, 8, width, height,
|
||||||
|
width * 3, pixbuf_destroy,
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
struct fp_driver *drv;
|
||||||
|
enum fp_scan_type scan_type;
|
||||||
|
const char *message;
|
||||||
|
|
||||||
|
drv = fp_dscv_dev_get_driver (win->ddev);
|
||||||
|
scan_type = fp_driver_get_scan_type(drv);
|
||||||
|
|
||||||
|
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 (struct fp_dev *dev,
|
||||||
|
int result,
|
||||||
|
struct fp_img *img,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
LibfprintDemoWindow *win = user_data;
|
||||||
|
|
||||||
|
if (result < 0) {
|
||||||
|
libfprint_demo_set_mode (win, ERROR_MODE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fp_async_capture_stop (dev, NULL, NULL);
|
||||||
|
|
||||||
|
win->img = img;
|
||||||
|
update_image (win);
|
||||||
|
|
||||||
|
libfprint_demo_set_mode (win, CAPTURE_MODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dev_open_cb (struct fp_dev *dev, int status, void *user_data)
|
||||||
|
{
|
||||||
|
LibfprintDemoWindow *win = user_data;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (status < 0) {
|
||||||
|
libfprint_demo_set_mode (win, ERROR_MODE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
libfprint_demo_set_capture_label (win);
|
||||||
|
|
||||||
|
win->dev = dev;
|
||||||
|
r = fp_async_capture_start (win->dev, FALSE, dev_capture_start_cb, user_data);
|
||||||
|
if (r < 0) {
|
||||||
|
g_warning ("fp_async_capture_start failed: %d", r);
|
||||||
|
libfprint_demo_set_mode (win, ERROR_MODE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
activate_capture (GSimpleAction *action,
|
||||||
|
GVariant *parameter,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
LibfprintDemoWindow *win = user_data;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
libfprint_demo_set_mode (win, SPINNER_MODE);
|
||||||
|
g_clear_pointer (&win->img, fp_img_free);
|
||||||
|
|
||||||
|
if (win->dev != NULL) {
|
||||||
|
dev_open_cb (win->dev, 0, user_data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
libfprint_demo_set_spinner_label (win, "Opening fingerprint reader");
|
||||||
|
|
||||||
|
r = fp_async_dev_open (win->ddev, dev_open_cb, user_data);
|
||||||
|
if (r < 0) {
|
||||||
|
g_warning ("fp_async_dev_open failed: %d", r);
|
||||||
|
libfprint_demo_set_mode (win, ERROR_MODE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 }
|
||||||
|
};
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
struct fp_driver *drv;
|
||||||
|
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_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_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);
|
||||||
|
|
||||||
|
drv = fp_dscv_dev_get_driver (win->ddev);
|
||||||
|
title = g_strdup_printf ("%s Test", fp_driver_get_full_name (drv));
|
||||||
|
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_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_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)
|
||||||
|
{
|
||||||
|
struct fp_dscv_dev **discovered_devs;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (fp_init () < 0) {
|
||||||
|
libfprint_demo_set_mode (window, ERROR_MODE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_pollfds ();
|
||||||
|
|
||||||
|
discovered_devs = fp_discover_devs();
|
||||||
|
if (!discovered_devs) {
|
||||||
|
libfprint_demo_set_mode (window, ERROR_MODE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Empty list? */
|
||||||
|
if (discovered_devs[0] == NULL) {
|
||||||
|
fp_dscv_devs_free (discovered_devs);
|
||||||
|
libfprint_demo_set_mode (window, EMPTY_MODE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fp_driver_supports_imaging(fp_dscv_dev_get_driver(discovered_devs[0]))) {
|
||||||
|
libfprint_demo_set_mode (window, NOIMAGING_MODE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
window->ddev = discovered_devs[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, 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
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>
|
||||||
351
demo/gtk-libfprint-test.ui
Normal file
351
demo/gtk-libfprint-test.ui
Normal file
@@ -0,0 +1,351 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- Generated with glade 3.22.1 -->
|
||||||
|
<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 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="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>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<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>
|
||||||
|
<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="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>
|
||||||
|
</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="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">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>
|
||||||
|
</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>
|
||||||
196
demo/loop.c
Normal file
196
demo/loop.c
Normal file
@@ -0,0 +1,196 @@
|
|||||||
|
/*
|
||||||
|
* fprint D-Bus daemon
|
||||||
|
* Copyright (C) 2008 Daniel Drake <dsd@gentoo.org>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <libfprint/fprint.h>
|
||||||
|
|
||||||
|
#include <poll.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "loop.h"
|
||||||
|
|
||||||
|
struct fdsource {
|
||||||
|
GSource source;
|
||||||
|
GSList *pollfds;
|
||||||
|
};
|
||||||
|
|
||||||
|
static gboolean source_prepare(GSource *source, gint *timeout)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
struct timeval tv;
|
||||||
|
|
||||||
|
r = fp_get_next_timeout(&tv);
|
||||||
|
if (r == 0) {
|
||||||
|
*timeout = -1;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!timerisset(&tv))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
*timeout = (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean source_check(GSource *source)
|
||||||
|
{
|
||||||
|
struct fdsource *_fdsource = (struct fdsource *) source;
|
||||||
|
GSList *l;
|
||||||
|
struct timeval tv;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (!_fdsource->pollfds)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
for (l = _fdsource->pollfds; l != NULL; l = l->next) {
|
||||||
|
GPollFD *pollfd = l->data;
|
||||||
|
|
||||||
|
if (pollfd->revents)
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = fp_get_next_timeout(&tv);
|
||||||
|
if (r == 1 && !timerisset(&tv))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean source_dispatch(GSource *source, GSourceFunc callback,
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
struct timeval zerotimeout = {
|
||||||
|
.tv_sec = 0,
|
||||||
|
.tv_usec = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* FIXME error handling */
|
||||||
|
fp_handle_events_timeout(&zerotimeout);
|
||||||
|
|
||||||
|
/* FIXME whats the return value used for? */
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void source_finalize(GSource *source)
|
||||||
|
{
|
||||||
|
struct fdsource *_fdsource = (struct fdsource *) source;
|
||||||
|
GSList *l;
|
||||||
|
|
||||||
|
if (!_fdsource->pollfds)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (l = _fdsource->pollfds; l != NULL; l = l->next) {
|
||||||
|
GPollFD *pollfd = l->data;
|
||||||
|
|
||||||
|
g_source_remove_poll((GSource *) _fdsource, pollfd);
|
||||||
|
g_slice_free(GPollFD, pollfd);
|
||||||
|
_fdsource->pollfds = g_slist_delete_link(_fdsource->pollfds, l);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_slist_free(_fdsource->pollfds);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GSourceFuncs sourcefuncs = {
|
||||||
|
.prepare = source_prepare,
|
||||||
|
.check = source_check,
|
||||||
|
.dispatch = source_dispatch,
|
||||||
|
.finalize = source_finalize,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct fdsource *fdsource = NULL;
|
||||||
|
|
||||||
|
static void pollfd_add(int fd, short events)
|
||||||
|
{
|
||||||
|
GPollFD *pollfd;
|
||||||
|
|
||||||
|
pollfd = g_slice_new(GPollFD);
|
||||||
|
pollfd->fd = fd;
|
||||||
|
pollfd->events = 0;
|
||||||
|
pollfd->revents = 0;
|
||||||
|
if (events & POLLIN)
|
||||||
|
pollfd->events |= G_IO_IN;
|
||||||
|
if (events & POLLOUT)
|
||||||
|
pollfd->events |= G_IO_OUT;
|
||||||
|
|
||||||
|
fdsource->pollfds = g_slist_prepend(fdsource->pollfds, pollfd);
|
||||||
|
g_source_add_poll((GSource *) fdsource, pollfd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pollfd_added_cb(int fd, short events)
|
||||||
|
{
|
||||||
|
g_debug("now monitoring fd %d", fd);
|
||||||
|
pollfd_add(fd, events);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pollfd_removed_cb(int fd)
|
||||||
|
{
|
||||||
|
GSList *l;
|
||||||
|
|
||||||
|
g_debug("no longer monitoring fd %d", fd);
|
||||||
|
|
||||||
|
if (!fdsource->pollfds) {
|
||||||
|
g_debug("cannot remove from list as list is empty?");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (l = fdsource->pollfds; l != NULL; l = l->next) {
|
||||||
|
GPollFD *pollfd = l->data;
|
||||||
|
|
||||||
|
if (pollfd->fd != fd)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
g_source_remove_poll((GSource *) fdsource, pollfd);
|
||||||
|
g_slice_free(GPollFD, pollfd);
|
||||||
|
fdsource->pollfds = g_slist_delete_link(fdsource->pollfds, l);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_error("couldn't find fd %d in list\n", fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
int setup_pollfds(void)
|
||||||
|
{
|
||||||
|
ssize_t numfds;
|
||||||
|
size_t i;
|
||||||
|
struct fp_pollfd *fpfds;
|
||||||
|
GSource *gsource;
|
||||||
|
|
||||||
|
gsource = g_source_new(&sourcefuncs, sizeof(struct fdsource));
|
||||||
|
fdsource = (struct fdsource *) gsource;
|
||||||
|
fdsource->pollfds = NULL;
|
||||||
|
|
||||||
|
numfds = fp_get_pollfds(&fpfds);
|
||||||
|
if (numfds < 0) {
|
||||||
|
if (fpfds)
|
||||||
|
free(fpfds);
|
||||||
|
return (int) numfds;
|
||||||
|
} else if (numfds > 0) {
|
||||||
|
for (i = 0; i < numfds; i++) {
|
||||||
|
struct fp_pollfd *fpfd = &fpfds[i];
|
||||||
|
pollfd_add(fpfd->fd, fpfd->events);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(fpfds);
|
||||||
|
fp_set_pollfd_notifiers(pollfd_added_cb, pollfd_removed_cb);
|
||||||
|
g_source_attach(gsource, NULL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
27
demo/loop.h
Normal file
27
demo/loop.h
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2008 Daniel Drake <dsd@gentoo.org>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef POLL_H
|
||||||
|
|
||||||
|
#define POLL_H
|
||||||
|
|
||||||
|
int setup_pollfds(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
30
demo/meson.build
Normal file
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', 'loop.c', 'loop.h', gtk_test_resources ],
|
||||||
|
dependencies: [ libfprint_dep, gtk_dep ],
|
||||||
|
include_directories: [
|
||||||
|
root_inc,
|
||||||
|
],
|
||||||
|
c_args: [ common_cflags,
|
||||||
|
'-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
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
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
|
||||||
51
demo/org.freedesktop.libfprint.Demo.json
Normal file
51
demo/org.freedesktop.libfprint.Demo.json
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
{
|
||||||
|
"app-id": "org.freedesktop.libfprint.Demo",
|
||||||
|
"runtime": "org.gnome.Platform",
|
||||||
|
"runtime-version": "master",
|
||||||
|
"sdk": "org.gnome.Sdk",
|
||||||
|
"command": "gtk-libfprint-test",
|
||||||
|
"finish-args": [
|
||||||
|
/* X11 + XShm access */
|
||||||
|
"--share=ipc", "--socket=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/libusb/COPYING"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "libfprint",
|
||||||
|
"buildsystem": "meson",
|
||||||
|
"config-opts": [ "-Dudev_rules=false", "-Dx11-examples=false", "-Dgtk-examples=true" ],
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://gitlab.freedesktop.org/libfprint/libfprint.git",
|
||||||
|
"branch": "wip/hadess/gtk-example"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
BIN
demo/org.freedesktop.libfprint.Demo.png
Normal file
BIN
demo/org.freedesktop.libfprint.Demo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
@@ -1,10 +0,0 @@
|
|||||||
EXTRA_DIST = doxygen.cfg
|
|
||||||
|
|
||||||
docs: doxygen.cfg
|
|
||||||
doxygen $^
|
|
||||||
|
|
||||||
docs-upload: docs
|
|
||||||
ln -s html api
|
|
||||||
ncftpput -f ~/.ncftp/reactivated -m -R httpdocs/fprint api/
|
|
||||||
rm -f api
|
|
||||||
|
|
||||||
115
doc/advanced-topics.xml
Normal file
115
doc/advanced-topics.xml
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
||||||
|
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
|
||||||
|
]>
|
||||||
|
<chapter id="advanced-topics" xmlns:xi="http://www.w3.org/2003/XInclude">
|
||||||
|
<title>Advanced Topics</title>
|
||||||
|
|
||||||
|
<refsect2 id="compatibility">
|
||||||
|
<title>Device and print compatibility</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Moving off generic conceptual ideas and onto libfprint-specific
|
||||||
|
implementation details, here are some introductory notes regarding how
|
||||||
|
libfprint copes with compatibility of fingerprints.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
libfprint deals with a whole variety of different fingerprint readers and
|
||||||
|
the design includes considerations of compatibility and interoperability
|
||||||
|
between multiple devices. Your application should also be prepared to
|
||||||
|
work with more than one type of fingerprint reader and should consider that
|
||||||
|
enrolled fingerprint X may not be compatible with the device the user has
|
||||||
|
plugged in today.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
libfprint implements the principle that fingerprints from different devices
|
||||||
|
are not necessarily compatible. For example, different devices may see
|
||||||
|
significantly different areas of fingerprint surface, and comparing images
|
||||||
|
between the devices would be unreliable. Also, devices can stretch and
|
||||||
|
distort images in different ways.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
libfprint also implements the principle that in some cases, fingerprints
|
||||||
|
<emphasis>are</emphasis> compatible between different devices. If you go and buy two
|
||||||
|
identical fingerprint readers, it seems logical that you should be able
|
||||||
|
to enroll on one and verify on another without problems.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
libfprint takes a fairly simplistic approach to these issues. Internally,
|
||||||
|
fingerprint hardware is driven by individual drivers. libfprint enforces
|
||||||
|
that a fingerprint that came from a device backed by driver X is never
|
||||||
|
compared to a fingerprint that came from a device backed by driver Y.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Additionally, libfprint is designed for the situation where a single driver
|
||||||
|
may support a range of devices which differ in imaging or scanning
|
||||||
|
properties. For example, a driver may support two ranges of devices which
|
||||||
|
even though are programmed over the same interface, one device sees
|
||||||
|
substantially less of the finger flesh, therefore images from the two
|
||||||
|
device types should be incompatible despite being from the same driver. To
|
||||||
|
implement this, each driver assigns a <emphasis>device type</emphasis> to each device
|
||||||
|
that it detects based on its imaging characteristics. libfprint ensures that
|
||||||
|
two prints being compared have the same device type.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
In summary, libfprint represents fingerprints in several internal structures
|
||||||
|
and each representation will offer you a way of determining the
|
||||||
|
<ulink url="#driver_id">driver ID</ulink> and <ulink url="#device-types">devtype</ulink> of the print in
|
||||||
|
question. Prints are only compatible if the driver ID <emphasis role="strong">and</emphasis> devtypes
|
||||||
|
match. libfprint does offer you some "is this print compatible?" helper
|
||||||
|
functions, so you don't have to worry about these details too much.
|
||||||
|
</para>
|
||||||
|
</refsect2>
|
||||||
|
|
||||||
|
<refsect2 id="driver_id">
|
||||||
|
<title>Driver IDs</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Each driver is assigned a unique ID by the project maintainer. These
|
||||||
|
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>
|
||||||
|
The only reason you may be interested in retrieving the driver ID for a
|
||||||
|
driver is for the purpose of checking if some print data is compatible
|
||||||
|
with a device. libfprint uses the driver ID as one way of checking that
|
||||||
|
the print you are trying to verify is compatible with the device in
|
||||||
|
question - it ensures that enrollment data from one driver is never fed to
|
||||||
|
another. Note that libfprint does provide you with helper functions to
|
||||||
|
determine whether a print is compatible with a device, so under most
|
||||||
|
circumstances, you don't have to worry about driver IDs at all.
|
||||||
|
</para>
|
||||||
|
</refsect2>
|
||||||
|
|
||||||
|
<refsect2 id="device-types">
|
||||||
|
<title>Device types</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Internally, the <ulink url="libfprint-Driver-operations.html#libfprint-Driver-operations.description">driver</ulink> behind a device assigns a 32-bit
|
||||||
|
<emphasis>devtype</emphasis> identifier to the device. This cannot be used as a unique
|
||||||
|
ID for a specific device as many devices under the same range may share
|
||||||
|
the same devtype. The devtype may even be 0 in all cases.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The only reason you may be interested in retrieving the devtype for a
|
||||||
|
device is for the purpose of checking if some print data is compatible
|
||||||
|
with a device. libfprint uses the devtype as one way of checking that the
|
||||||
|
print you are verifying is compatible with the device in question - the
|
||||||
|
devtypes must be equal. This effectively allows drivers to support more
|
||||||
|
than one type of device where the data from each one is not compatible with
|
||||||
|
the other. Note that libfprint does provide you with helper functions to
|
||||||
|
determine whether a print is compatible with a device, so under most
|
||||||
|
circumstances, you don't have to worry about devtypes at all.
|
||||||
|
</para>
|
||||||
|
</refsect2>
|
||||||
|
|
||||||
|
</chapter>
|
||||||
1294
doc/doxygen.cfg
1294
doc/doxygen.cfg
File diff suppressed because it is too large
Load Diff
30
doc/getting-started.xml
Normal file
30
doc/getting-started.xml
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
||||||
|
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
|
||||||
|
]>
|
||||||
|
<chapter id="getting-started" xmlns:xi="http://www.w3.org/2003/XInclude">
|
||||||
|
<title>Getting Started</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
libfprint includes several simple functional examples under the <computeroutput>examples/</computeroutput>
|
||||||
|
directory in the libfprint source distribution. Those are good starting
|
||||||
|
points.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Usually the first thing you want to do is determine which fingerprint
|
||||||
|
devices are present. This is done through <ulink url="libfprint-Device-discovery.html">device discovery</ulink>.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
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,
|
||||||
|
image capture, and verification.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
That should be enough to get you started, but do remember there are
|
||||||
|
documentation pages on other aspects of libfprint's API (see the modules
|
||||||
|
page).
|
||||||
|
</para>
|
||||||
|
</chapter>
|
||||||
106
doc/intro.xml
Normal file
106
doc/intro.xml
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
||||||
|
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
|
||||||
|
]>
|
||||||
|
<chapter id="intro" xmlns:xi="http://www.w3.org/2003/XInclude">
|
||||||
|
<title>Introduction</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
libfprint is an open source library to provide access to fingerprint
|
||||||
|
scanning devices. For more info, see the
|
||||||
|
<ulink url="https://fprint.freedesktop.org/">libfprint project homepage</ulink>.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This documentation is aimed at application developers who wish to integrate
|
||||||
|
fingerprint-related functionality into their software. libfprint has been
|
||||||
|
designed so that you only have to do this once – by integrating your
|
||||||
|
software with libfprint, you'll be supporting all the fingerprint readers
|
||||||
|
that we have got our hands on. As such, the API is rather general (and
|
||||||
|
therefore hopefully easy to comprehend!), and does its best to hide the
|
||||||
|
technical details that required to operate the hardware.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This documentation is not aimed at developers wishing to develop and
|
||||||
|
contribute fingerprint device drivers to libfprint.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Feedback on this API and its associated documentation is appreciated. Was
|
||||||
|
anything unclear? Does anything seem unreasonably complicated? Is anything
|
||||||
|
missing? Let us know on the
|
||||||
|
<ulink url="https://lists.freedesktop.org/mailman/listinfo/fprint">mailing list</ulink>.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<refsect2 id="enrollment">
|
||||||
|
<title>Enrollment</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Before you dive into the API, it's worth introducing a couple of concepts.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The process of enrolling a finger is where you effectively scan your
|
||||||
|
finger for the purposes of teaching the system what your finger looks like.
|
||||||
|
This means that you scan your fingerprint, then the system processes it and
|
||||||
|
stores some data about your fingerprint to refer to later.
|
||||||
|
</para>
|
||||||
|
</refsect2>
|
||||||
|
|
||||||
|
<refsect2 id="verification">
|
||||||
|
<title>Verification</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Verification is what most people think of when they think about fingerprint
|
||||||
|
scanning. The process of verification is effectively performing a fresh
|
||||||
|
fingerprint scan, and then comparing that scan to a finger that was
|
||||||
|
previously enrolled.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
As an example scenario, verification can be used to implement what people
|
||||||
|
would picture as fingerprint login (i.e. fingerprint replaces password).
|
||||||
|
For example:
|
||||||
|
</para>
|
||||||
|
<itemizedlist mark='dot'>
|
||||||
|
<listitem>
|
||||||
|
I enroll my fingerprint through some software that trusts I am who I say
|
||||||
|
I am. This is a prerequisite before I can perform fingerprint-based
|
||||||
|
login for my account.
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
Some time later, I want to login to my computer. I enter my username,
|
||||||
|
but instead of prompting me for a password, it asks me to scan my finger.
|
||||||
|
I scan my finger.
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
The system compares the finger I just scanned to the one that was
|
||||||
|
enrolled earlier. If the system decides that the fingerprints match,
|
||||||
|
I am successfully logged in. Otherwise, the system informs me that I am
|
||||||
|
not authorised to login as that user.
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
</refsect2>
|
||||||
|
|
||||||
|
<refsect2 id="identification">
|
||||||
|
<title>Identification</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Identification is the process of comparing a freshly scanned fingerprint
|
||||||
|
to a <emphasis>collection</emphasis> of previously enrolled fingerprints. For example,
|
||||||
|
imagine there are 100 people in an organisation, and they all have enrolled
|
||||||
|
their fingerprints. One user walks up to a fingerprint scanner and scans
|
||||||
|
their finger. With <emphasis>no other knowledge</emphasis> of who that user might be,
|
||||||
|
the system examines their fingerprint, looks in the database, and determines
|
||||||
|
that the user is user number #61.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
In other words, verification might be seen as a one-to-one fingerprint
|
||||||
|
comparison where you know the identity of the user that you wish to
|
||||||
|
authenticate, whereas identification is a one-to-many comparison where you
|
||||||
|
do not know the identity of the user that you wish to authenticate.
|
||||||
|
</para>
|
||||||
|
</refsect2>
|
||||||
|
</chapter>
|
||||||
73
doc/libfprint-docs.xml
Normal file
73
doc/libfprint-docs.xml
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
||||||
|
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd"
|
||||||
|
[
|
||||||
|
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
|
||||||
|
]>
|
||||||
|
<book id="index">
|
||||||
|
<bookinfo>
|
||||||
|
<title>libfprint Reference Manual</title>
|
||||||
|
<releaseinfo>
|
||||||
|
<para>This document is the API reference for the libfprint library.</para>
|
||||||
|
<para>
|
||||||
|
The latest version of libfprint, as well as the latest version of
|
||||||
|
this API reference, is <ulink role="online-location" url="https://fprint.freedesktop.org/libfprint-dev/">available online</ulink>.
|
||||||
|
</para>
|
||||||
|
</releaseinfo>
|
||||||
|
</bookinfo>
|
||||||
|
|
||||||
|
<part>
|
||||||
|
<title>Library Overview</title>
|
||||||
|
<xi:include href="intro.xml"/>
|
||||||
|
<xi:include href="advanced-topics.xml"/>
|
||||||
|
<xi:include href="getting-started.xml"/>
|
||||||
|
</part>
|
||||||
|
|
||||||
|
<part>
|
||||||
|
<title>Library API Documentation</title>
|
||||||
|
<xi:include href="xml/events.xml"/>
|
||||||
|
<xi:include href="xml/discovery.xml"/>
|
||||||
|
|
||||||
|
<xi:include href="xml/drv.xml"/>
|
||||||
|
<xi:include href="xml/dev.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>
|
||||||
|
<title>Writing Drivers</title>
|
||||||
|
<chapter id="driver-helpers">
|
||||||
|
<title>Logging, and async machinery</title>
|
||||||
|
<xi:include href="xml/fpi-log.xml"/>
|
||||||
|
<xi:include href="xml/fpi-ssm.xml"/>
|
||||||
|
<xi:include href="xml/fpi-poll.xml"/>
|
||||||
|
</chapter>
|
||||||
|
|
||||||
|
<chapter id="driver-dev">
|
||||||
|
<title>Device and driver structures</title>
|
||||||
|
<xi:include href="xml/fpi-dev.xml"/>
|
||||||
|
<xi:include href="xml/fpi-dev-img.xml"/>
|
||||||
|
<xi:include href="xml/fpi-core.xml"/>
|
||||||
|
<xi:include href="xml/fpi-core-img.xml"/>
|
||||||
|
</chapter>
|
||||||
|
|
||||||
|
<chapter id="driver-img">
|
||||||
|
<title>Image manipulation</title>
|
||||||
|
<xi:include href="xml/fpi-img.xml"/>
|
||||||
|
<xi:include href="xml/fpi-assembling.xml"/>
|
||||||
|
</chapter>
|
||||||
|
|
||||||
|
<xi:include href="xml/fpi-usb.xml"/>
|
||||||
|
</part>
|
||||||
|
|
||||||
|
<index id="api-index">
|
||||||
|
<title>API Index</title>
|
||||||
|
<xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include>
|
||||||
|
</index>
|
||||||
|
<index id="deprecated-api-index" role="deprecated">
|
||||||
|
<title>Index of deprecated API</title>
|
||||||
|
<xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include>
|
||||||
|
</index>
|
||||||
|
</book>
|
||||||
271
doc/libfprint-sections.txt
Normal file
271
doc/libfprint-sections.txt
Normal file
@@ -0,0 +1,271 @@
|
|||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<INCLUDE>fprint.h</INCLUDE>
|
||||||
|
<FILE>events</FILE>
|
||||||
|
<TITLE>Initialisation and events handling</TITLE>
|
||||||
|
LIBFPRINT_DEPRECATED
|
||||||
|
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>
|
||||||
|
<INCLUDE>fprint.h</INCLUDE>
|
||||||
|
<FILE>discovery</FILE>
|
||||||
|
<TITLE>Device discovery</TITLE>
|
||||||
|
fp_dscv_dev
|
||||||
|
fp_discover_devs
|
||||||
|
fp_dscv_devs_free
|
||||||
|
fp_dscv_dev_get_driver
|
||||||
|
fp_dscv_dev_get_devtype
|
||||||
|
fp_dscv_dev_get_driver_id
|
||||||
|
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>
|
||||||
|
<INCLUDE>fprint.h</INCLUDE>
|
||||||
|
<FILE>drv</FILE>
|
||||||
|
fp_driver
|
||||||
|
fp_driver_get_name
|
||||||
|
fp_driver_get_full_name
|
||||||
|
fp_driver_get_driver_id
|
||||||
|
fp_driver_get_scan_type
|
||||||
|
fp_driver_supports_imaging
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<INCLUDE>fprint.h</INCLUDE>
|
||||||
|
<FILE>dev</FILE>
|
||||||
|
fp_dev
|
||||||
|
fp_scan_type
|
||||||
|
fp_capture_result
|
||||||
|
fp_enroll_result
|
||||||
|
fp_verify_result
|
||||||
|
|
||||||
|
fp_dev_get_driver
|
||||||
|
fp_dev_get_nr_enroll_stages
|
||||||
|
fp_dev_get_devtype
|
||||||
|
fp_dev_supports_print_data
|
||||||
|
fp_dev_supports_imaging
|
||||||
|
fp_dev_supports_identification
|
||||||
|
fp_dev_supports_dscv_print
|
||||||
|
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>
|
||||||
|
<INCLUDE>fprint.h</INCLUDE>
|
||||||
|
<FILE>print_data</FILE>
|
||||||
|
fp_finger
|
||||||
|
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>
|
||||||
|
<INCLUDE>fprint.h</INCLUDE>
|
||||||
|
<FILE>dscv_print</FILE>
|
||||||
|
fp_dscv_print
|
||||||
|
fp_discover_prints
|
||||||
|
fp_dscv_prints_free
|
||||||
|
fp_dscv_print_get_driver_id
|
||||||
|
fp_dscv_print_get_devtype
|
||||||
|
fp_dscv_print_get_finger
|
||||||
|
fp_dscv_print_delete
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<INCLUDE>fprint.h</INCLUDE>
|
||||||
|
<FILE>img</FILE>
|
||||||
|
fp_img
|
||||||
|
fp_minutia
|
||||||
|
fp_img_free
|
||||||
|
fp_img_get_height
|
||||||
|
fp_img_get_width
|
||||||
|
fp_img_get_data
|
||||||
|
fp_img_save_to_file
|
||||||
|
fp_img_standardize
|
||||||
|
fp_img_binarize
|
||||||
|
fp_img_get_minutiae
|
||||||
|
fp_minutia_get_coords
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<INCLUDE>fpi-log.h</INCLUDE>
|
||||||
|
<FILE>fpi-log</FILE>
|
||||||
|
fp_dbg
|
||||||
|
fp_info
|
||||||
|
fp_warn
|
||||||
|
fp_err
|
||||||
|
BUG_ON
|
||||||
|
BUG
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<INCLUDE>fpi-ssm.h</INCLUDE>
|
||||||
|
<FILE>fpi-ssm</FILE>
|
||||||
|
fpi_ssm
|
||||||
|
ssm_completed_fn
|
||||||
|
ssm_handler_fn
|
||||||
|
|
||||||
|
fpi_ssm_new
|
||||||
|
fpi_ssm_free
|
||||||
|
fpi_ssm_start
|
||||||
|
fpi_ssm_start_subsm
|
||||||
|
|
||||||
|
fpi_ssm_next_state
|
||||||
|
fpi_ssm_next_state_timeout_cb
|
||||||
|
fpi_ssm_jump_to_state
|
||||||
|
fpi_ssm_mark_completed
|
||||||
|
fpi_ssm_mark_failed
|
||||||
|
fpi_ssm_get_user_data
|
||||||
|
fpi_ssm_get_error
|
||||||
|
fpi_ssm_get_cur_state
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<INCLUDE>fpi-poll.h</INCLUDE>
|
||||||
|
<FILE>fpi-poll</FILE>
|
||||||
|
fpi_timeout
|
||||||
|
fpi_timeout_fn
|
||||||
|
fpi_timeout_add
|
||||||
|
fpi_timeout_set_name
|
||||||
|
fpi_timeout_cancel
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<INCLUDE>fpi-dev.h</INCLUDE>
|
||||||
|
<FILE>fpi-dev</FILE>
|
||||||
|
fp_img_dev
|
||||||
|
|
||||||
|
FP_DEV
|
||||||
|
FP_IMG_DEV
|
||||||
|
fp_dev_set_instance_data
|
||||||
|
FP_INSTANCE_DATA
|
||||||
|
|
||||||
|
fpi_dev_get_usb_dev
|
||||||
|
fpi_dev_get_verify_data
|
||||||
|
fpi_dev_set_nr_enroll_stages
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<INCLUDE>fpi-dev-img.h</INCLUDE>
|
||||||
|
<FILE>fpi-dev-img</FILE>
|
||||||
|
fp_imgdev_action
|
||||||
|
fp_imgdev_state
|
||||||
|
fp_imgdev_enroll_state
|
||||||
|
|
||||||
|
fpi_imgdev_abort_scan
|
||||||
|
fpi_imgdev_activate_complete
|
||||||
|
fpi_imgdev_close_complete
|
||||||
|
fpi_imgdev_deactivate_complete
|
||||||
|
fpi_imgdev_get_action
|
||||||
|
fpi_imgdev_get_action_result
|
||||||
|
fpi_imgdev_get_action_state
|
||||||
|
fpi_imgdev_image_captured
|
||||||
|
fpi_imgdev_open_complete
|
||||||
|
fpi_imgdev_report_finger_status
|
||||||
|
fpi_imgdev_session_error
|
||||||
|
fpi_imgdev_set_action_result
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<INCLUDE>fpi-core.h</INCLUDE>
|
||||||
|
<FILE>fpi-core</FILE>
|
||||||
|
usb_id
|
||||||
|
fp_driver_type
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<INCLUDE>fpi-core.h</INCLUDE>
|
||||||
|
<FILE>fpi-core-img</FILE>
|
||||||
|
FpiImgDriverFlags
|
||||||
|
fp_img_driver
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<INCLUDE>fpi-img.h</INCLUDE>
|
||||||
|
<FILE>fpi-img</FILE>
|
||||||
|
FpiImgFlags
|
||||||
|
|
||||||
|
fpi_img_new
|
||||||
|
fpi_img_new_for_imgdev
|
||||||
|
fpi_img_realloc
|
||||||
|
fpi_img_resize
|
||||||
|
|
||||||
|
fpi_std_sq_dev
|
||||||
|
fpi_mean_sq_diff_norm
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<INCLUDE>fpi-assembling.h</INCLUDE>
|
||||||
|
<FILE>fpi-assembling</FILE>
|
||||||
|
fpi_frame
|
||||||
|
fpi_frame_asmbl_ctx
|
||||||
|
fpi_line_asmbl_ctx
|
||||||
|
|
||||||
|
fpi_do_movement_estimation
|
||||||
|
fpi_assemble_frames
|
||||||
|
fpi_assemble_lines
|
||||||
|
</SECTION>
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<INCLUDE>fpi-usb.h</INCLUDE>
|
||||||
|
<FILE>fpi-usb</FILE>
|
||||||
|
fpi_usb_transfer
|
||||||
|
|
||||||
|
fpi_usb_transfer_cb_fn
|
||||||
|
fpi_usb_alloc
|
||||||
|
fpi_usb_fill_bulk_transfer
|
||||||
|
fpi_usb_submit_transfer
|
||||||
|
fpi_usb_cancel_transfer
|
||||||
|
</SECTION>
|
||||||
71
doc/meson.build
Normal file
71
doc/meson.build
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
subdir('xml')
|
||||||
|
|
||||||
|
private_headers = [
|
||||||
|
'config.h',
|
||||||
|
|
||||||
|
'aeslib.h',
|
||||||
|
'assembling.h',
|
||||||
|
'fp_internal.h',
|
||||||
|
'nbis-helpers.h',
|
||||||
|
'fpi-async.h',
|
||||||
|
'fpi-data.h',
|
||||||
|
|
||||||
|
# Drivers
|
||||||
|
'aes1660.h',
|
||||||
|
'aes2501.h',
|
||||||
|
'aes2550.h',
|
||||||
|
'aes2660.h',
|
||||||
|
'aes3k.h',
|
||||||
|
'aesx660.h',
|
||||||
|
'driver_ids.h',
|
||||||
|
'elan.h',
|
||||||
|
'upek_proto.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',
|
||||||
|
'mytime.h',
|
||||||
|
]
|
||||||
|
|
||||||
|
html_images = [
|
||||||
|
]
|
||||||
|
|
||||||
|
content_files = [
|
||||||
|
'intro.xml'
|
||||||
|
]
|
||||||
|
|
||||||
|
expand_content_files = content_files
|
||||||
|
|
||||||
|
glib_prefix = dependency('glib-2.0').get_pkgconfig_variable('prefix')
|
||||||
|
glib_docpath = join_paths(glib_prefix, 'share', 'gtk-doc', 'html')
|
||||||
|
docpath = join_paths(get_option('datadir'), 'gtk-doc', 'html')
|
||||||
|
|
||||||
|
gnome.gtkdoc('libfprint',
|
||||||
|
main_xml: 'libfprint-docs.xml',
|
||||||
|
src_dir: join_paths(meson.source_root(), 'libfprint'),
|
||||||
|
dependencies: libfprint_dep,
|
||||||
|
content_files: content_files,
|
||||||
|
expand_content_files: expand_content_files,
|
||||||
|
scan_args: [
|
||||||
|
'--ignore-decorators=API_EXPORTED',
|
||||||
|
'--ignore-headers=' + ' '.join(private_headers),
|
||||||
|
],
|
||||||
|
fixxref_args: [
|
||||||
|
'--html-dir=@0@'.format(docpath),
|
||||||
|
'--extra-dir=@0@'.format(join_paths(glib_docpath, 'glib')),
|
||||||
|
'--extra-dir=@0@'.format(join_paths(glib_docpath, 'gobject')),
|
||||||
|
],
|
||||||
|
html_assets: html_images,
|
||||||
|
install: true)
|
||||||
8
doc/xml/gtkdocentities.ent.in
Normal file
8
doc/xml/gtkdocentities.ent.in
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<!ENTITY package "@PACKAGE@">
|
||||||
|
<!ENTITY package_bugreport "@PACKAGE_BUGREPORT@">
|
||||||
|
<!ENTITY package_name "@PACKAGE_NAME@">
|
||||||
|
<!ENTITY package_string "@PACKAGE_STRING@">
|
||||||
|
<!ENTITY package_tarname "@PACKAGE_TARNAME@">
|
||||||
|
<!ENTITY package_url "@PACKAGE_URL@">
|
||||||
|
<!ENTITY package_version "@PACKAGE_VERSION@">
|
||||||
|
<!ENTITY package_api_version "@PACKAGE_API_VERSION@">
|
||||||
10
doc/xml/meson.build
Normal file
10
doc/xml/meson.build
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
ent_conf = configuration_data()
|
||||||
|
ent_conf.set('PACKAGE', 'libfprint')
|
||||||
|
ent_conf.set('PACKAGE_BUGREPORT', 'https://gitlab.freedesktop.org/libfprint/libfprint/issues')
|
||||||
|
ent_conf.set('PACKAGE_NAME', 'libfprint')
|
||||||
|
ent_conf.set('PACKAGE_STRING', 'libfprint')
|
||||||
|
ent_conf.set('PACKAGE_TARNAME', 'libfprint-' + meson.project_version())
|
||||||
|
ent_conf.set('PACKAGE_URL', 'https://fprint.freedesktop.org/')
|
||||||
|
ent_conf.set('PACKAGE_VERSION', meson.project_version())
|
||||||
|
ent_conf.set('PACKAGE_API_VERSION', '1.0')
|
||||||
|
configure_file(input: 'gtkdocentities.ent.in', output: 'gtkdocentities.ent', configuration: ent_conf)
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
AM_CFLAGS = -I$(top_srcdir)
|
|
||||||
noinst_PROGRAMS = verify_live enroll verify img_capture cpp-test
|
|
||||||
|
|
||||||
verify_live_SOURCES = verify_live.c
|
|
||||||
verify_live_LDADD = ../libfprint/libfprint.la
|
|
||||||
|
|
||||||
enroll_SOURCES = enroll.c
|
|
||||||
enroll_LDADD = ../libfprint/libfprint.la
|
|
||||||
|
|
||||||
verify_SOURCES = verify.c
|
|
||||||
verify_LDADD = ../libfprint/libfprint.la
|
|
||||||
|
|
||||||
img_capture_SOURCES = img_capture.c
|
|
||||||
img_capture_LDADD = ../libfprint/libfprint.la
|
|
||||||
|
|
||||||
cpp_test_SOURCES = cpp-test.cpp
|
|
||||||
cpp_test_LDADD = ../libfprint/libfprint.la
|
|
||||||
|
|
||||||
if BUILD_X11_EXAMPLES
|
|
||||||
noinst_PROGRAMS += img_capture_continuous
|
|
||||||
|
|
||||||
img_capture_continuous_CFLAGS = $(X_CFLAGS) $(XV_CFLAGS)
|
|
||||||
img_capture_continuous_SOURCES = img_capture_continuous.c
|
|
||||||
img_capture_continuous_LDADD = ../libfprint/libfprint.la $(X_LIBS) $(X_PRE_LIBS) $(XV_LIBS) -lX11 $(X_EXTRA_LIBS);
|
|
||||||
endif
|
|
||||||
|
|
||||||
@@ -24,6 +24,8 @@
|
|||||||
|
|
||||||
#include <libfprint/fprint.h>
|
#include <libfprint/fprint.h>
|
||||||
|
|
||||||
|
#include "storage.h"
|
||||||
|
|
||||||
struct fp_dscv_dev *discover_device(struct fp_dscv_dev **discovered_devs)
|
struct fp_dscv_dev *discover_device(struct fp_dscv_dev **discovered_devs)
|
||||||
{
|
{
|
||||||
struct fp_dscv_dev *ddev = discovered_devs[0];
|
struct fp_dscv_dev *ddev = discovered_devs[0];
|
||||||
@@ -46,7 +48,6 @@ struct fp_print_data *enroll(struct fp_dev *dev) {
|
|||||||
do {
|
do {
|
||||||
struct fp_img *img = NULL;
|
struct fp_img *img = NULL;
|
||||||
|
|
||||||
sleep(1);
|
|
||||||
printf("\nScan your finger now.\n");
|
printf("\nScan your finger now.\n");
|
||||||
|
|
||||||
r = fp_enroll_finger_img(dev, &enrolled_print, &img);
|
r = fp_enroll_finger_img(dev, &enrolled_print, &img);
|
||||||
@@ -110,12 +111,14 @@ int main(void)
|
|||||||
"Ctrl+C\n");
|
"Ctrl+C\n");
|
||||||
getchar();
|
getchar();
|
||||||
|
|
||||||
|
setenv ("G_MESSAGES_DEBUG", "all", 0);
|
||||||
|
setenv ("LIBUSB_DEBUG", "3", 0);
|
||||||
|
|
||||||
r = fp_init();
|
r = fp_init();
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
fprintf(stderr, "Failed to initialize libfprint\n");
|
fprintf(stderr, "Failed to initialize libfprint\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
fp_set_debug(3);
|
|
||||||
|
|
||||||
discovered_devs = fp_discover_devs();
|
discovered_devs = fp_discover_devs();
|
||||||
if (!discovered_devs) {
|
if (!discovered_devs) {
|
||||||
@@ -141,7 +144,7 @@ int main(void)
|
|||||||
if (!data)
|
if (!data)
|
||||||
goto out_close;
|
goto out_close;
|
||||||
|
|
||||||
r = fp_print_data_save(data, RIGHT_INDEX);
|
r = print_data_save(data, RIGHT_INDEX);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
fprintf(stderr, "Data save failed, code %d\n", r);
|
fprintf(stderr, "Data save failed, code %d\n", r);
|
||||||
|
|
||||||
|
|||||||
@@ -42,12 +42,14 @@ int main(void)
|
|||||||
struct fp_dev *dev;
|
struct fp_dev *dev;
|
||||||
struct fp_img *img = NULL;
|
struct fp_img *img = NULL;
|
||||||
|
|
||||||
|
setenv ("G_MESSAGES_DEBUG", "all", 0);
|
||||||
|
setenv ("LIBUSB_DEBUG", "3", 0);
|
||||||
|
|
||||||
r = fp_init();
|
r = fp_init();
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
fprintf(stderr, "Failed to initialize libfprint\n");
|
fprintf(stderr, "Failed to initialize libfprint\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
fp_set_debug(3);
|
|
||||||
|
|
||||||
discovered_devs = fp_discover_devs();
|
discovered_devs = fp_discover_devs();
|
||||||
if (!discovered_devs) {
|
if (!discovered_devs) {
|
||||||
@@ -57,6 +59,7 @@ int main(void)
|
|||||||
|
|
||||||
ddev = discover_device(discovered_devs);
|
ddev = discover_device(discovered_devs);
|
||||||
if (!ddev) {
|
if (!ddev) {
|
||||||
|
fp_dscv_devs_free(discovered_devs);
|
||||||
fprintf(stderr, "No devices detected.\n");
|
fprintf(stderr, "No devices detected.\n");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ static int connection = -1;
|
|||||||
static void grey2yuy2 (unsigned char *grey, char *YUV, int num) {
|
static void grey2yuy2 (unsigned char *grey, char *YUV, int num) {
|
||||||
int i, j;
|
int i, j;
|
||||||
int y0, y1, u0, u1, v0, v1;
|
int y0, y1, u0, u1, v0, v1;
|
||||||
int gval;
|
uint64_t gval;
|
||||||
|
|
||||||
for (i = 0, j = 0; i < num; i += 2, j += 4)
|
for (i = 0, j = 0; i < num; i += 2, j += 4)
|
||||||
{
|
{
|
||||||
@@ -84,7 +84,7 @@ static void display_frame(struct fp_img *img)
|
|||||||
0, 0, width, height, 0, 0, width, height);
|
0, 0, width, height, 0, 0, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void QueryXv()
|
static void QueryXv(void)
|
||||||
{
|
{
|
||||||
unsigned int num_adaptors;
|
unsigned int num_adaptors;
|
||||||
int num_formats;
|
int num_formats;
|
||||||
@@ -141,12 +141,14 @@ int main(void)
|
|||||||
int img_height;
|
int img_height;
|
||||||
int standardize = 0;
|
int standardize = 0;
|
||||||
|
|
||||||
|
setenv ("G_MESSAGES_DEBUG", "all", 0);
|
||||||
|
setenv ("LIBUSB_DEBUG", "3", 0);
|
||||||
|
|
||||||
r = fp_init();
|
r = fp_init();
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
fprintf(stderr, "Failed to initialize libfprint\n");
|
fprintf(stderr, "Failed to initialize libfprint\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
fp_set_debug(3);
|
|
||||||
|
|
||||||
discovered_devs = fp_discover_devs();
|
discovered_devs = fp_discover_devs();
|
||||||
if (!discovered_devs) {
|
if (!discovered_devs) {
|
||||||
|
|||||||
29
examples/meson.build
Normal file
29
examples/meson.build
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
|
||||||
|
examples = [ 'verify_live', 'enroll', 'verify', 'img_capture' ]
|
||||||
|
foreach example: examples
|
||||||
|
executable(example,
|
||||||
|
[example + '.c', 'storage.c'],
|
||||||
|
dependencies: [libfprint_dep, glib_dep],
|
||||||
|
include_directories: [
|
||||||
|
root_inc,
|
||||||
|
],
|
||||||
|
c_args: common_cflags)
|
||||||
|
endforeach
|
||||||
|
|
||||||
|
executable('cpp-test',
|
||||||
|
'cpp-test.cpp',
|
||||||
|
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
|
||||||
136
examples/storage.c
Normal file
136
examples/storage.c
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <libfprint/fprint.h>
|
||||||
|
|
||||||
|
#define STORAGE_FILE "test-storage.variant"
|
||||||
|
|
||||||
|
static char *
|
||||||
|
get_print_data_descriptor (struct fp_print_data *data, struct fp_dev *dev, enum fp_finger finger)
|
||||||
|
{
|
||||||
|
gint drv_id;
|
||||||
|
gint devtype;
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
drv_id = fp_print_data_get_driver_id (data);
|
||||||
|
devtype = fp_print_data_get_devtype (data);
|
||||||
|
} else {
|
||||||
|
drv_id = fp_driver_get_driver_id(fp_dev_get_driver (dev));
|
||||||
|
devtype = fp_dev_get_devtype (dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
return g_strdup_printf("%x/%08x/%x",
|
||||||
|
drv_id,
|
||||||
|
devtype,
|
||||||
|
finger);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GVariantDict*
|
||||||
|
load_data(void)
|
||||||
|
{
|
||||||
|
GVariantDict *res;
|
||||||
|
GVariant *var;
|
||||||
|
gchar *contents = NULL;
|
||||||
|
gssize 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, NULL, NULL);
|
||||||
|
|
||||||
|
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(struct fp_print_data *fp_data, enum fp_finger finger)
|
||||||
|
{
|
||||||
|
gchar *descr = get_print_data_descriptor (fp_data, NULL, finger);
|
||||||
|
GVariantDict *dict;
|
||||||
|
GVariant *val;
|
||||||
|
guchar *data;
|
||||||
|
gsize size;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
dict = load_data();
|
||||||
|
|
||||||
|
size = fp_print_data_get_data(fp_data, &data);
|
||||||
|
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));
|
||||||
|
g_variant_dict_unref(dict);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct fp_print_data*
|
||||||
|
print_data_load(struct fp_dev *dev, enum fp_finger finger)
|
||||||
|
{
|
||||||
|
gchar *descr = get_print_data_descriptor (NULL, dev, finger);
|
||||||
|
GVariantDict *dict;
|
||||||
|
guchar *stored_data;
|
||||||
|
gsize stored_len;
|
||||||
|
GVariant *val;
|
||||||
|
struct fp_print_data *res = NULL;
|
||||||
|
|
||||||
|
dict = load_data();
|
||||||
|
val = g_variant_dict_lookup_value (dict, descr, G_VARIANT_TYPE ("ay"));
|
||||||
|
|
||||||
|
if (val) {
|
||||||
|
stored_data = (guchar*) g_variant_get_fixed_array (val, &stored_len, 1);
|
||||||
|
res = fp_print_data_from_data(stored_data, stored_len);
|
||||||
|
|
||||||
|
g_variant_unref(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_variant_dict_unref(dict);
|
||||||
|
g_free(descr);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
27
examples/storage.h
Normal file
27
examples/storage.h
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __STORAGE_H
|
||||||
|
#define __STORAGE_H
|
||||||
|
|
||||||
|
int print_data_save(struct fp_print_data *fp_data, enum fp_finger finger);
|
||||||
|
struct fp_print_data* print_data_load(struct fp_dev *dev, enum fp_finger finger);
|
||||||
|
|
||||||
|
#endif /* __STORAGE_H */
|
||||||
@@ -24,6 +24,8 @@
|
|||||||
|
|
||||||
#include <libfprint/fprint.h>
|
#include <libfprint/fprint.h>
|
||||||
|
|
||||||
|
#include "storage.h"
|
||||||
|
|
||||||
struct fp_dscv_dev *discover_device(struct fp_dscv_dev **discovered_devs)
|
struct fp_dscv_dev *discover_device(struct fp_dscv_dev **discovered_devs)
|
||||||
{
|
{
|
||||||
struct fp_dscv_dev *ddev = discovered_devs[0];
|
struct fp_dscv_dev *ddev = discovered_devs[0];
|
||||||
@@ -86,12 +88,14 @@ int main(void)
|
|||||||
struct fp_dev *dev;
|
struct fp_dev *dev;
|
||||||
struct fp_print_data *data;
|
struct fp_print_data *data;
|
||||||
|
|
||||||
|
setenv ("G_MESSAGES_DEBUG", "all", 0);
|
||||||
|
setenv ("LIBUSB_DEBUG", "3", 0);
|
||||||
|
|
||||||
r = fp_init();
|
r = fp_init();
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
fprintf(stderr, "Failed to initialize libfprint\n");
|
fprintf(stderr, "Failed to initialize libfprint\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
fp_set_debug(3);
|
|
||||||
|
|
||||||
discovered_devs = fp_discover_devs();
|
discovered_devs = fp_discover_devs();
|
||||||
if (!discovered_devs) {
|
if (!discovered_devs) {
|
||||||
@@ -115,8 +119,8 @@ int main(void)
|
|||||||
printf("Opened device. Loading previously enrolled right index finger "
|
printf("Opened device. Loading previously enrolled right index finger "
|
||||||
"data...\n");
|
"data...\n");
|
||||||
|
|
||||||
r = fp_print_data_load(dev, RIGHT_INDEX, &data);
|
data = print_data_load(dev, RIGHT_INDEX);
|
||||||
if (r != 0) {
|
if (!data) {
|
||||||
fprintf(stderr, "Failed to load fingerprint, error %d\n", r);
|
fprintf(stderr, "Failed to load fingerprint, error %d\n", r);
|
||||||
fprintf(stderr, "Did you remember to enroll your right index finger "
|
fprintf(stderr, "Did you remember to enroll your right index finger "
|
||||||
"first?\n");
|
"first?\n");
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ struct fp_print_data *enroll(struct fp_dev *dev) {
|
|||||||
"complete the process.\n", fp_dev_get_nr_enroll_stages(dev));
|
"complete the process.\n", fp_dev_get_nr_enroll_stages(dev));
|
||||||
|
|
||||||
do {
|
do {
|
||||||
sleep(1);
|
|
||||||
printf("\nScan your finger now.\n");
|
printf("\nScan your finger now.\n");
|
||||||
r = fp_enroll_finger(dev, &enrolled_print);
|
r = fp_enroll_finger(dev, &enrolled_print);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
@@ -129,12 +128,14 @@ int main(void)
|
|||||||
struct fp_dev *dev;
|
struct fp_dev *dev;
|
||||||
struct fp_print_data *data;
|
struct fp_print_data *data;
|
||||||
|
|
||||||
|
setenv ("G_MESSAGES_DEBUG", "all", 0);
|
||||||
|
setenv ("LIBUSB_DEBUG", "3", 0);
|
||||||
|
|
||||||
r = fp_init();
|
r = fp_init();
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
fprintf(stderr, "Failed to initialize libfprint\n");
|
fprintf(stderr, "Failed to initialize libfprint\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
fp_set_debug(3);
|
|
||||||
|
|
||||||
discovered_devs = fp_discover_devs();
|
discovered_devs = fp_discover_devs();
|
||||||
if (!discovered_devs) {
|
if (!discovered_devs) {
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
prefix=@prefix@
|
|
||||||
exec_prefix=@exec_prefix@
|
|
||||||
libdir=@libdir@
|
|
||||||
includedir=@includedir@
|
|
||||||
|
|
||||||
Name: libfprint
|
|
||||||
Description: Generic C API for fingerprint reader access
|
|
||||||
Version: @VERSION@
|
|
||||||
Libs: -L${libdir} -lfprint
|
|
||||||
Cflags: -I${includedir}/libfprint
|
|
||||||
|
|
||||||
@@ -1,217 +0,0 @@
|
|||||||
lib_LTLIBRARIES = libfprint.la
|
|
||||||
noinst_PROGRAMS = fprint-list-udev-rules
|
|
||||||
MOSTLYCLEANFILES = $(udev_rules_DATA)
|
|
||||||
|
|
||||||
UPEKE2_SRC = drivers/upeke2.c
|
|
||||||
UPEKTS_SRC = drivers/upekts.c
|
|
||||||
UPEKTC_SRC = drivers/upektc.c drivers/upektc.h
|
|
||||||
UPEKSONLY_SRC = drivers/upeksonly.c
|
|
||||||
URU4000_SRC = drivers/uru4000.c
|
|
||||||
AES1610_SRC = drivers/aes1610.c
|
|
||||||
AES1660_SRC = drivers/aes1660.c drivers/aes1660.h
|
|
||||||
AES2501_SRC = drivers/aes2501.c drivers/aes2501.h
|
|
||||||
AES2550_SRC = drivers/aes2550.c drivers/aes2550.h
|
|
||||||
AES2660_SRC = drivers/aes2660.c drivers/aes2660.h
|
|
||||||
AES3500_SRC = drivers/aes3500.c
|
|
||||||
AES4000_SRC = drivers/aes4000.c
|
|
||||||
FDU2000_SRC = drivers/fdu2000.c
|
|
||||||
VCOM5S_SRC = drivers/vcom5s.c
|
|
||||||
VFS101_SRC = drivers/vfs101.c
|
|
||||||
VFS301_SRC = drivers/vfs301.c drivers/vfs301_proto.c drivers/vfs301_proto.h drivers/vfs301_proto_fragments.h
|
|
||||||
VFS5011_SRC = drivers/vfs5011.c drivers/vfs5011_proto.h
|
|
||||||
UPEKTC_IMG_SRC = drivers/upektc_img.c drivers/upektc_img.h
|
|
||||||
ETES603_SRC = drivers/etes603.c
|
|
||||||
|
|
||||||
EXTRA_DIST = \
|
|
||||||
$(UPEKE2_SRC) \
|
|
||||||
$(UPEKTS_SRC) \
|
|
||||||
$(UPEKTC_SRC) \
|
|
||||||
$(UPEKSONLY_SRC) \
|
|
||||||
$(URU4000_SRC) \
|
|
||||||
$(AES1610_SRC) \
|
|
||||||
$(AES1660_SRC) \
|
|
||||||
$(AES2501_SRC) \
|
|
||||||
$(AES2550_SRC) \
|
|
||||||
$(AES2660_SRC) \
|
|
||||||
$(AES3500_SRC) \
|
|
||||||
$(AES4000_SRC) \
|
|
||||||
$(FDU2000_SRC) \
|
|
||||||
$(VCOM5S_SRC) \
|
|
||||||
$(VFS101_SRC) \
|
|
||||||
$(VFS301_SRC) \
|
|
||||||
$(VFS5011_SRC) \
|
|
||||||
$(UPEKTC_IMG_SRC) \
|
|
||||||
$(ETES603_SRC) \
|
|
||||||
drivers/aesx660.c \
|
|
||||||
drivers/aesx660.h \
|
|
||||||
drivers/aes3k.c \
|
|
||||||
drivers/aes3k.h \
|
|
||||||
drivers/driver_ids.h \
|
|
||||||
aeslib.c aeslib.h \
|
|
||||||
pixman.c \
|
|
||||||
60-fprint-autosuspend.rules
|
|
||||||
|
|
||||||
DRIVER_SRC =
|
|
||||||
OTHER_SRC =
|
|
||||||
|
|
||||||
NBIS_SRC = \
|
|
||||||
nbis/include/bozorth.h \
|
|
||||||
nbis/include/bz_array.h \
|
|
||||||
nbis/include/defs.h \
|
|
||||||
nbis/include/lfs.h \
|
|
||||||
nbis/include/log.h \
|
|
||||||
nbis/include/morph.h \
|
|
||||||
nbis/include/sunrast.h \
|
|
||||||
nbis/bozorth3/bozorth3.c \
|
|
||||||
nbis/bozorth3/bz_alloc.c \
|
|
||||||
nbis/bozorth3/bz_drvrs.c \
|
|
||||||
nbis/bozorth3/bz_gbls.c \
|
|
||||||
nbis/bozorth3/bz_io.c \
|
|
||||||
nbis/bozorth3/bz_sort.c \
|
|
||||||
nbis/mindtct/binar.c \
|
|
||||||
nbis/mindtct/block.c \
|
|
||||||
nbis/mindtct/contour.c \
|
|
||||||
nbis/mindtct/detect.c \
|
|
||||||
nbis/mindtct/dft.c \
|
|
||||||
nbis/mindtct/free.c \
|
|
||||||
nbis/mindtct/globals.c \
|
|
||||||
nbis/mindtct/imgutil.c \
|
|
||||||
nbis/mindtct/init.c \
|
|
||||||
nbis/mindtct/line.c \
|
|
||||||
nbis/mindtct/log.c \
|
|
||||||
nbis/mindtct/loop.c \
|
|
||||||
nbis/mindtct/maps.c \
|
|
||||||
nbis/mindtct/matchpat.c \
|
|
||||||
nbis/mindtct/minutia.c \
|
|
||||||
nbis/mindtct/morph.c \
|
|
||||||
nbis/mindtct/quality.c \
|
|
||||||
nbis/mindtct/remove.c \
|
|
||||||
nbis/mindtct/ridges.c \
|
|
||||||
nbis/mindtct/shape.c \
|
|
||||||
nbis/mindtct/sort.c \
|
|
||||||
nbis/mindtct/util.c
|
|
||||||
|
|
||||||
libfprint_la_CFLAGS = -fvisibility=hidden -I$(srcdir)/nbis/include $(LIBUSB_CFLAGS) $(GLIB_CFLAGS) $(CRYPTO_CFLAGS) $(AM_CFLAGS)
|
|
||||||
libfprint_la_LDFLAGS = -version-info @lt_major@:@lt_revision@:@lt_age@
|
|
||||||
libfprint_la_LIBADD = -lm $(LIBUSB_LIBS) $(GLIB_LIBS) $(CRYPTO_LIBS)
|
|
||||||
|
|
||||||
fprint_list_udev_rules_SOURCES = fprint-list-udev-rules.c
|
|
||||||
fprint_list_udev_rules_CFLAGS = -fvisibility=hidden -I$(srcdir)/nbis/include $(LIBUSB_CFLAGS) $(GLIB_CFLAGS) $(CRYPTO_CFLAGS) $(AM_CFLAGS)
|
|
||||||
fprint_list_udev_rules_LDADD = $(builddir)/libfprint.la $(GLIB_LIBS)
|
|
||||||
|
|
||||||
udev_rules_DATA = 60-fprint-autosuspend.rules
|
|
||||||
|
|
||||||
if ENABLE_UDEV_RULES
|
|
||||||
$(udev_rules_DATA): fprint-list-udev-rules
|
|
||||||
$(builddir)/fprint-list-udev-rules > $@
|
|
||||||
endif
|
|
||||||
|
|
||||||
if ENABLE_UPEKE2
|
|
||||||
DRIVER_SRC += $(UPEKE2_SRC)
|
|
||||||
endif
|
|
||||||
|
|
||||||
if ENABLE_UPEKTS
|
|
||||||
DRIVER_SRC += $(UPEKTS_SRC)
|
|
||||||
endif
|
|
||||||
|
|
||||||
if ENABLE_UPEKSONLY
|
|
||||||
DRIVER_SRC += $(UPEKSONLY_SRC)
|
|
||||||
endif
|
|
||||||
|
|
||||||
if ENABLE_UPEKTC
|
|
||||||
DRIVER_SRC += $(UPEKTC_SRC)
|
|
||||||
endif
|
|
||||||
|
|
||||||
if ENABLE_URU4000
|
|
||||||
DRIVER_SRC += $(URU4000_SRC)
|
|
||||||
endif
|
|
||||||
|
|
||||||
if ENABLE_VCOM5S
|
|
||||||
DRIVER_SRC += $(VCOM5S_SRC)
|
|
||||||
endif
|
|
||||||
|
|
||||||
#if ENABLE_FDU2000
|
|
||||||
#DRIVER_SRC += $(FDU2000_SRC)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if ENABLE_AES1610
|
|
||||||
DRIVER_SRC += $(AES1610_SRC)
|
|
||||||
endif
|
|
||||||
|
|
||||||
if ENABLE_AES1660
|
|
||||||
DRIVER_SRC += $(AES1660_SRC)
|
|
||||||
endif
|
|
||||||
|
|
||||||
if ENABLE_AES2501
|
|
||||||
DRIVER_SRC += $(AES2501_SRC)
|
|
||||||
endif
|
|
||||||
|
|
||||||
if ENABLE_AES2550
|
|
||||||
DRIVER_SRC += $(AES2550_SRC)
|
|
||||||
endif
|
|
||||||
|
|
||||||
if ENABLE_AES2660
|
|
||||||
DRIVER_SRC += $(AES2660_SRC)
|
|
||||||
endif
|
|
||||||
|
|
||||||
if ENABLE_AES3500
|
|
||||||
DRIVER_SRC += $(AES3500_SRC)
|
|
||||||
endif
|
|
||||||
|
|
||||||
if ENABLE_AES4000
|
|
||||||
DRIVER_SRC += $(AES4000_SRC)
|
|
||||||
endif
|
|
||||||
|
|
||||||
if ENABLE_VFS101
|
|
||||||
DRIVER_SRC += $(VFS101_SRC)
|
|
||||||
endif
|
|
||||||
|
|
||||||
if ENABLE_VFS301
|
|
||||||
DRIVER_SRC += $(VFS301_SRC)
|
|
||||||
endif
|
|
||||||
|
|
||||||
if ENABLE_VFS5011
|
|
||||||
DRIVER_SRC += $(VFS5011_SRC)
|
|
||||||
endif
|
|
||||||
|
|
||||||
if ENABLE_UPEKTC_IMG
|
|
||||||
DRIVER_SRC += $(UPEKTC_IMG_SRC)
|
|
||||||
endif
|
|
||||||
|
|
||||||
if ENABLE_ETES603
|
|
||||||
DRIVER_SRC += $(ETES603_SRC)
|
|
||||||
endif
|
|
||||||
|
|
||||||
if REQUIRE_PIXMAN
|
|
||||||
OTHER_SRC += pixman.c
|
|
||||||
libfprint_la_CFLAGS += $(IMAGING_CFLAGS)
|
|
||||||
libfprint_la_LIBADD += $(IMAGING_LIBS)
|
|
||||||
endif
|
|
||||||
|
|
||||||
if REQUIRE_AESLIB
|
|
||||||
OTHER_SRC += aeslib.c aeslib.h
|
|
||||||
endif
|
|
||||||
|
|
||||||
if REQUIRE_AESX660
|
|
||||||
OTHER_SRC += drivers/aesx660.c drivers/aesx660.h
|
|
||||||
endif
|
|
||||||
|
|
||||||
if REQUIRE_AES3K
|
|
||||||
OTHER_SRC += drivers/aes3k.c drivers/aes3k.h
|
|
||||||
endif
|
|
||||||
|
|
||||||
libfprint_la_SOURCES = \
|
|
||||||
fp_internal.h \
|
|
||||||
async.c \
|
|
||||||
core.c \
|
|
||||||
data.c \
|
|
||||||
drv.c \
|
|
||||||
img.c \
|
|
||||||
imgdev.c \
|
|
||||||
poll.c \
|
|
||||||
sync.c \
|
|
||||||
$(DRIVER_SRC) \
|
|
||||||
$(OTHER_SRC) \
|
|
||||||
$(NBIS_SRC)
|
|
||||||
|
|
||||||
pkginclude_HEADERS = fprint.h
|
|
||||||
@@ -1,425 +0,0 @@
|
|||||||
/*
|
|
||||||
* Shared functions between libfprint Authentec drivers
|
|
||||||
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define FP_COMPONENT "aeslib"
|
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <libusb.h>
|
|
||||||
#include <glib.h>
|
|
||||||
|
|
||||||
#include "fp_internal.h"
|
|
||||||
#include "aeslib.h"
|
|
||||||
|
|
||||||
#define MAX_REGWRITES_PER_REQUEST 16
|
|
||||||
|
|
||||||
#define BULK_TIMEOUT 4000
|
|
||||||
#define EP_IN (1 | LIBUSB_ENDPOINT_IN)
|
|
||||||
#define EP_OUT (2 | LIBUSB_ENDPOINT_OUT)
|
|
||||||
|
|
||||||
struct write_regv_data {
|
|
||||||
struct fp_img_dev *imgdev;
|
|
||||||
unsigned int num_regs;
|
|
||||||
const struct aes_regwrite *regs;
|
|
||||||
unsigned int offset;
|
|
||||||
aes_write_regv_cb callback;
|
|
||||||
void *user_data;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void continue_write_regv(struct write_regv_data *wdata);
|
|
||||||
|
|
||||||
/* libusb bulk callback for regv write completion transfer. continues the
|
|
||||||
* transaction */
|
|
||||||
static void write_regv_trf_complete(struct libusb_transfer *transfer)
|
|
||||||
{
|
|
||||||
struct write_regv_data *wdata = transfer->user_data;
|
|
||||||
|
|
||||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
|
|
||||||
wdata->callback(wdata->imgdev, -EIO, wdata->user_data);
|
|
||||||
else if (transfer->length != transfer->actual_length)
|
|
||||||
wdata->callback(wdata->imgdev, -EPROTO, wdata->user_data);
|
|
||||||
else
|
|
||||||
continue_write_regv(wdata);
|
|
||||||
|
|
||||||
g_free(transfer->buffer);
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* write from wdata->offset to upper_bound (inclusive) of wdata->regs */
|
|
||||||
static int do_write_regv(struct write_regv_data *wdata, int upper_bound)
|
|
||||||
{
|
|
||||||
unsigned int offset = wdata->offset;
|
|
||||||
unsigned int num = upper_bound - offset + 1;
|
|
||||||
size_t alloc_size = num * 2;
|
|
||||||
unsigned char *data = g_malloc(alloc_size);
|
|
||||||
unsigned int i;
|
|
||||||
size_t data_offset = 0;
|
|
||||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
|
||||||
int r;
|
|
||||||
|
|
||||||
if (!transfer) {
|
|
||||||
g_free(data);
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = offset; i < offset + num; i++) {
|
|
||||||
const struct aes_regwrite *regwrite = &wdata->regs[i];
|
|
||||||
data[data_offset++] = regwrite->reg;
|
|
||||||
data[data_offset++] = regwrite->value;
|
|
||||||
}
|
|
||||||
|
|
||||||
libusb_fill_bulk_transfer(transfer, wdata->imgdev->udev, EP_OUT, data,
|
|
||||||
alloc_size, write_regv_trf_complete, wdata, BULK_TIMEOUT);
|
|
||||||
r = libusb_submit_transfer(transfer);
|
|
||||||
if (r < 0) {
|
|
||||||
g_free(data);
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
}
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* write the next batch of registers to be written, or if there are no more,
|
|
||||||
* indicate completion to the caller */
|
|
||||||
static void continue_write_regv(struct write_regv_data *wdata)
|
|
||||||
{
|
|
||||||
unsigned int offset = wdata->offset;
|
|
||||||
unsigned int regs_remaining;
|
|
||||||
unsigned int limit;
|
|
||||||
unsigned int upper_bound;
|
|
||||||
int i;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
/* skip all zeros and ensure there is still work to do */
|
|
||||||
while (TRUE) {
|
|
||||||
if (offset >= wdata->num_regs) {
|
|
||||||
fp_dbg("all registers written");
|
|
||||||
wdata->callback(wdata->imgdev, 0, wdata->user_data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (wdata->regs[offset].reg)
|
|
||||||
break;
|
|
||||||
offset++;
|
|
||||||
}
|
|
||||||
|
|
||||||
wdata->offset = offset;
|
|
||||||
regs_remaining = wdata->num_regs - offset;
|
|
||||||
limit = MIN(regs_remaining, MAX_REGWRITES_PER_REQUEST);
|
|
||||||
upper_bound = offset + limit - 1;
|
|
||||||
|
|
||||||
/* determine if we can write the entire of the regs at once, or if there
|
|
||||||
* is a zero dividing things up */
|
|
||||||
for (i = offset; i <= upper_bound; i++)
|
|
||||||
if (!wdata->regs[i].reg) {
|
|
||||||
upper_bound = i - 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = do_write_regv(wdata, upper_bound);
|
|
||||||
if (r < 0) {
|
|
||||||
wdata->callback(wdata->imgdev, r, wdata->user_data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
wdata->offset = upper_bound + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* write a load of registers to the device, combining multiple writes in a
|
|
||||||
* single URB up to a limit. insert writes to non-existent register 0 to force
|
|
||||||
* specific groups of writes to be separated by different URBs. */
|
|
||||||
void aes_write_regv(struct fp_img_dev *dev, const struct aes_regwrite *regs,
|
|
||||||
unsigned int num_regs, aes_write_regv_cb callback, void *user_data)
|
|
||||||
{
|
|
||||||
struct write_regv_data *wdata = g_malloc(sizeof(*wdata));
|
|
||||||
fp_dbg("write %d regs", num_regs);
|
|
||||||
wdata->imgdev = dev;
|
|
||||||
wdata->num_regs = num_regs;
|
|
||||||
wdata->regs = regs;
|
|
||||||
wdata->offset = 0;
|
|
||||||
wdata->callback = callback;
|
|
||||||
wdata->user_data = user_data;
|
|
||||||
continue_write_regv(wdata);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline unsigned char aes_get_pixel(struct aes_stripe *frame,
|
|
||||||
unsigned int x,
|
|
||||||
unsigned int y,
|
|
||||||
unsigned int frame_width,
|
|
||||||
unsigned int frame_height)
|
|
||||||
{
|
|
||||||
unsigned char ret;
|
|
||||||
|
|
||||||
ret = frame->data[x * (frame_height >> 1) + (y >> 1)];
|
|
||||||
ret = y % 2 ? ret >> 4 : ret & 0xf;
|
|
||||||
ret *= 17;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned int calc_error(struct aes_stripe *first_frame,
|
|
||||||
struct aes_stripe *second_frame,
|
|
||||||
int dx,
|
|
||||||
int dy,
|
|
||||||
unsigned int frame_width,
|
|
||||||
unsigned int frame_height)
|
|
||||||
{
|
|
||||||
unsigned int width, height;
|
|
||||||
unsigned int x1, y1, x2, y2, err, i, j;
|
|
||||||
|
|
||||||
width = frame_width - (dx > 0 ? dx : -dx);
|
|
||||||
height = 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 = aes_get_pixel(first_frame, x1, y1, frame_width, frame_height);
|
|
||||||
v2 = aes_get_pixel(second_frame, x2, y2, frame_width, frame_height);
|
|
||||||
err += v1 > v2 ? v1 - v2 : v2 - v1;
|
|
||||||
j++;
|
|
||||||
x1++;
|
|
||||||
x2++;
|
|
||||||
|
|
||||||
} while (j < width);
|
|
||||||
i++;
|
|
||||||
y1++;
|
|
||||||
y2++;
|
|
||||||
} while (i < height);
|
|
||||||
|
|
||||||
/* Normalize error */
|
|
||||||
err *= (frame_height * 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 aes_stripe *first_frame,
|
|
||||||
struct aes_stripe *second_frame,
|
|
||||||
unsigned int *min_error,
|
|
||||||
unsigned int frame_width,
|
|
||||||
unsigned int frame_height)
|
|
||||||
{
|
|
||||||
int dx, dy;
|
|
||||||
unsigned int err;
|
|
||||||
*min_error = INT_MAX;
|
|
||||||
|
|
||||||
/* 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 < frame_height; dy++) {
|
|
||||||
for (dx = -8; dx < 8; dx++) {
|
|
||||||
err = calc_error(first_frame, second_frame,
|
|
||||||
dx, dy, frame_width, frame_height);
|
|
||||||
if (err < *min_error) {
|
|
||||||
*min_error = err;
|
|
||||||
second_frame->delta_x = -dx;
|
|
||||||
second_frame->delta_y = dy;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int aes_calc_delta(GSList *stripes, size_t num_stripes,
|
|
||||||
unsigned int frame_width, unsigned int frame_height,
|
|
||||||
gboolean reverse)
|
|
||||||
{
|
|
||||||
GSList *list_entry = stripes;
|
|
||||||
GTimer *timer;
|
|
||||||
int frame = 1;
|
|
||||||
int height = 0;
|
|
||||||
struct aes_stripe *prev_stripe = list_entry->data;
|
|
||||||
unsigned int min_error;
|
|
||||||
|
|
||||||
list_entry = g_slist_next(list_entry);
|
|
||||||
|
|
||||||
timer = g_timer_new();
|
|
||||||
do {
|
|
||||||
struct aes_stripe *cur_stripe = list_entry->data;
|
|
||||||
|
|
||||||
if (reverse) {
|
|
||||||
find_overlap(prev_stripe, cur_stripe, &min_error,
|
|
||||||
frame_width, frame_height);
|
|
||||||
prev_stripe->delta_y = -prev_stripe->delta_y;
|
|
||||||
prev_stripe->delta_x = -prev_stripe->delta_x;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
find_overlap(cur_stripe, prev_stripe, &min_error,
|
|
||||||
frame_width, frame_height);
|
|
||||||
|
|
||||||
frame++;
|
|
||||||
height += prev_stripe->delta_y;
|
|
||||||
prev_stripe = cur_stripe;
|
|
||||||
list_entry = g_slist_next(list_entry);
|
|
||||||
|
|
||||||
} while (frame < num_stripes);
|
|
||||||
|
|
||||||
if (height < 0)
|
|
||||||
height = -height;
|
|
||||||
height += frame_height;
|
|
||||||
g_timer_stop(timer);
|
|
||||||
fp_dbg("calc delta completed in %f secs", g_timer_elapsed(timer, NULL));
|
|
||||||
g_timer_destroy(timer);
|
|
||||||
|
|
||||||
return height;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void aes_blit_stripe(struct fp_img *img,
|
|
||||||
struct aes_stripe *stripe,
|
|
||||||
int x, int y, unsigned int frame_width,
|
|
||||||
unsigned int frame_height)
|
|
||||||
{
|
|
||||||
unsigned int ix, iy;
|
|
||||||
unsigned int fx, fy;
|
|
||||||
unsigned int width, height;
|
|
||||||
|
|
||||||
/* Find intersection */
|
|
||||||
if (x < 0) {
|
|
||||||
width = frame_width + x;
|
|
||||||
ix = 0;
|
|
||||||
fx = -x;
|
|
||||||
} else {
|
|
||||||
ix = x;
|
|
||||||
fx = 0;
|
|
||||||
width = frame_width;
|
|
||||||
}
|
|
||||||
if ((ix + width) > img->width)
|
|
||||||
width = img->width - ix;
|
|
||||||
|
|
||||||
if (y < 0) {
|
|
||||||
iy = 0;
|
|
||||||
fy = -y;
|
|
||||||
height = frame_height + y;
|
|
||||||
} else {
|
|
||||||
iy = y;
|
|
||||||
fy = 0;
|
|
||||||
height = frame_height;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fx > frame_width)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (fy > 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)] = aes_get_pixel(stripe, fx, fy, frame_width, frame_height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct fp_img *aes_assemble(GSList *stripes, size_t stripes_len,
|
|
||||||
unsigned int frame_width, unsigned int frame_height, unsigned int img_width)
|
|
||||||
{
|
|
||||||
GSList *stripe;
|
|
||||||
struct fp_img *img;
|
|
||||||
int height = 0;
|
|
||||||
int i, y, x;
|
|
||||||
gboolean reverse = FALSE;
|
|
||||||
struct aes_stripe *aes_stripe;
|
|
||||||
|
|
||||||
BUG_ON(stripes_len == 0);
|
|
||||||
BUG_ON(img_width < frame_width);
|
|
||||||
|
|
||||||
/* Calculate height */
|
|
||||||
i = 0;
|
|
||||||
stripe = stripes;
|
|
||||||
|
|
||||||
/* No offset for 1st image */
|
|
||||||
aes_stripe = stripe->data;
|
|
||||||
aes_stripe->delta_x = 0;
|
|
||||||
aes_stripe->delta_y = 0;
|
|
||||||
do {
|
|
||||||
aes_stripe = stripe->data;
|
|
||||||
|
|
||||||
height += aes_stripe->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 += frame_height;
|
|
||||||
|
|
||||||
/* Create buffer big enough for max image */
|
|
||||||
img = fpi_img_new(img_width * height);
|
|
||||||
img->flags = FP_IMG_COLORS_INVERTED;
|
|
||||||
img->width = img_width;
|
|
||||||
img->height = height;
|
|
||||||
|
|
||||||
/* Assemble stripes */
|
|
||||||
i = 0;
|
|
||||||
stripe = stripes;
|
|
||||||
y = reverse ? (height - frame_height) : 0;
|
|
||||||
x = (img_width - frame_width) / 2;
|
|
||||||
|
|
||||||
do {
|
|
||||||
aes_stripe = stripe->data;
|
|
||||||
|
|
||||||
y += aes_stripe->delta_y;
|
|
||||||
x += aes_stripe->delta_x;
|
|
||||||
|
|
||||||
aes_blit_stripe(img, aes_stripe, x, y, frame_width, frame_height);
|
|
||||||
|
|
||||||
stripe = g_slist_next(stripe);
|
|
||||||
i++;
|
|
||||||
} while (i < stripes_len);
|
|
||||||
|
|
||||||
return img;
|
|
||||||
}
|
|
||||||
966
libfprint/core.c
966
libfprint/core.c
@@ -1,966 +0,0 @@
|
|||||||
/*
|
|
||||||
* Core functions for libfprint
|
|
||||||
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <config.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include <glib.h>
|
|
||||||
#include <libusb.h>
|
|
||||||
|
|
||||||
#include "fp_internal.h"
|
|
||||||
|
|
||||||
static int log_level = 0;
|
|
||||||
static int log_level_fixed = 0;
|
|
||||||
|
|
||||||
libusb_context *fpi_usb_ctx = NULL;
|
|
||||||
GSList *opened_devices = NULL;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \mainpage libfprint API Reference
|
|
||||||
* libfprint is an open source library to provide access to fingerprint
|
|
||||||
* scanning devices. For more info, see the
|
|
||||||
* <a href="http://www.reactivated.net/fprint/Libfprint">libfprint project
|
|
||||||
* homepage</a>.
|
|
||||||
*
|
|
||||||
* This documentation is aimed at application developers who wish to integrate
|
|
||||||
* fingerprint-related functionality into their software. libfprint has been
|
|
||||||
* designed so that you only have to do this once - by integrating your
|
|
||||||
* software with libfprint, you'll be supporting all the fingerprint readers
|
|
||||||
* that we have got our hands on. As such, the API is rather general (and
|
|
||||||
* therefore hopefully easy to comprehend!), and does its best to hide the
|
|
||||||
* technical details that required to operate the hardware.
|
|
||||||
*
|
|
||||||
* This documentation is not aimed at developers wishing to develop and
|
|
||||||
* contribute fingerprint device drivers to libfprint.
|
|
||||||
*
|
|
||||||
* Feedback on this API and its associated documentation is appreciated. Was
|
|
||||||
* anything unclear? Does anything seem unreasonably complicated? Is anything
|
|
||||||
* missing? Let us know on the
|
|
||||||
* <a href="http://www.reactivated.net/fprint/Mailing_list">mailing list</a>.
|
|
||||||
*
|
|
||||||
* \section enrollment Enrollment
|
|
||||||
*
|
|
||||||
* Before you dive into the API, it's worth introducing a couple of concepts.
|
|
||||||
*
|
|
||||||
* The process of enrolling a finger is where you effectively scan your
|
|
||||||
* finger for the purposes of teaching the system what your finger looks like.
|
|
||||||
* This means that you scan your fingerprint, then the system processes it and
|
|
||||||
* stores some data about your fingerprint to refer to later.
|
|
||||||
*
|
|
||||||
* \section verification Verification
|
|
||||||
*
|
|
||||||
* Verification is what most people think of when they think about fingerprint
|
|
||||||
* scanning. The process of verification is effectively performing a fresh
|
|
||||||
* fingerprint scan, and then comparing that scan to a finger that was
|
|
||||||
* previously enrolled.
|
|
||||||
*
|
|
||||||
* As an example scenario, verification can be used to implement what people
|
|
||||||
* would picture as fingerprint login (i.e. fingerprint replaces password).
|
|
||||||
* For example:
|
|
||||||
* - I enroll my fingerprint through some software that trusts I am who I say
|
|
||||||
* I am. This is a prerequisite before I can perform fingerprint-based
|
|
||||||
* login for my account.
|
|
||||||
* - Some time later, I want to login to my computer. I enter my username,
|
|
||||||
* but instead of prompting me for a password, it asks me to scan my finger.
|
|
||||||
* I scan my finger.
|
|
||||||
* - The system compares the finger I just scanned to the one that was
|
|
||||||
* enrolled earlier. If the system decides that the fingerprints match,
|
|
||||||
* I am successfully logged in. Otherwise, the system informs me that I am
|
|
||||||
* not authorised to login as that user.
|
|
||||||
*
|
|
||||||
* \section identification Identification
|
|
||||||
*
|
|
||||||
* Identification is the process of comparing a freshly scanned fingerprint
|
|
||||||
* to a <em>collection</em> of previously enrolled fingerprints. For example,
|
|
||||||
* imagine there are 100 people in an organisation, and they all have enrolled
|
|
||||||
* their fingerprints. One user walks up to a fingerprint scanner and scans
|
|
||||||
* their finger. With <em>no other knowledge</em> of who that user might be,
|
|
||||||
* the system examines their fingerprint, looks in the database, and determines
|
|
||||||
* that the user is user number #61.
|
|
||||||
*
|
|
||||||
* In other words, verification might be seen as a one-to-one fingerprint
|
|
||||||
* comparison where you know the identity of the user that you wish to
|
|
||||||
* authenticate, whereas identification is a one-to-many comparison where you
|
|
||||||
* do not know the identity of the user that you wish to authenticate.
|
|
||||||
*
|
|
||||||
* \section compat_general Device and print compatibility
|
|
||||||
* Moving off generic conceptual ideas and onto libfprint-specific
|
|
||||||
* implementation details, here are some introductory notes regarding how
|
|
||||||
* libfprint copes with compatibility of fingerprints.
|
|
||||||
*
|
|
||||||
* libfprint deals with a whole variety of different fingerprint readers and
|
|
||||||
* the design includes considerations of compatibility and interoperability
|
|
||||||
* between multiple devices. Your application should also be prepared to
|
|
||||||
* work with more than one type of fingerprint reader and should consider that
|
|
||||||
* enrolled fingerprint X may not be compatible with the device the user has
|
|
||||||
* plugged in today.
|
|
||||||
*
|
|
||||||
* libfprint implements the principle that fingerprints from different devices
|
|
||||||
* are not necessarily compatible. For example, different devices may see
|
|
||||||
* significantly different areas of fingerprint surface, and comparing images
|
|
||||||
* between the devices would be unreliable. Also, devices can stretch and
|
|
||||||
* distort images in different ways.
|
|
||||||
*
|
|
||||||
* libfprint also implements the principle that in some cases, fingerprints
|
|
||||||
* <em>are</em> compatible between different devices. If you go and buy two
|
|
||||||
* identical fingerprint readers, it seems logical that you should be able
|
|
||||||
* to enroll on one and verify on another without problems.
|
|
||||||
*
|
|
||||||
* libfprint takes a fairly simplistic approach to these issues. Internally,
|
|
||||||
* fingerprint hardware is driven by individual drivers. libfprint enforces
|
|
||||||
* that a fingerprint that came from a device backed by driver X is never
|
|
||||||
* compared to a fingerprint that came from a device backed by driver Y.
|
|
||||||
*
|
|
||||||
* Additionally, libfprint is designed for the situation where a single driver
|
|
||||||
* may support a range of devices which differ in imaging or scanning
|
|
||||||
* properties. For example, a driver may support two ranges of devices which
|
|
||||||
* even though are programmed over the same interface, one device sees
|
|
||||||
* substantially less of the finger flesh, therefore images from the two
|
|
||||||
* device types should be incompatible despite being from the same driver. To
|
|
||||||
* implement this, each driver assigns a <em>device type</em> to each device
|
|
||||||
* that it detects based on its imaging characteristics. libfprint ensures that
|
|
||||||
* two prints being compared have the same device type.
|
|
||||||
*
|
|
||||||
* In summary, libfprint represents fingerprints in several internal structures
|
|
||||||
* and each representation will offer you a way of determining the
|
|
||||||
* \ref driver_id "driver ID" and \ref devtype "devtype" of the print in
|
|
||||||
* question. Prints are only compatible if the driver ID <b>and</b> devtypes
|
|
||||||
* match. libfprint does offer you some "is this print compatible?" helper
|
|
||||||
* functions, so you don't have to worry about these details too much.
|
|
||||||
*
|
|
||||||
* \section sync Synchronity/asynchronity
|
|
||||||
*
|
|
||||||
* Currently, all data acquisition operations are synchronous and can
|
|
||||||
* potentially block for extended periods of time. For example, the enroll
|
|
||||||
* function will block for an unpredictable amount of time until the user
|
|
||||||
* scans their finger.
|
|
||||||
*
|
|
||||||
* Alternative asynchronous/non-blocking functionality will be offered in
|
|
||||||
* future but has not been implemented yet.
|
|
||||||
*
|
|
||||||
* \section getting_started Getting started
|
|
||||||
*
|
|
||||||
* libfprint includes several simple functional examples under the examples/
|
|
||||||
* directory in the libfprint source distribution. Those are good starting
|
|
||||||
* points.
|
|
||||||
*
|
|
||||||
* Usually the first thing you want to do is determine which fingerprint
|
|
||||||
* devices are present. This is done through \ref dscv_dev "device discovery".
|
|
||||||
*
|
|
||||||
* Once you have found a device you would like to operate, you should open it.
|
|
||||||
* Refer to \ref dev "device operations". This section also details enrollment,
|
|
||||||
* image capture, and verification.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* That should be enough to get you started, but do remember there are
|
|
||||||
* documentation pages on other aspects of libfprint's API (see the modules
|
|
||||||
* page).
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** @defgroup core Core library operations */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @defgroup dev Device operations
|
|
||||||
* In order to interact with fingerprint scanners, your software will
|
|
||||||
* interface primarily with libfprint's representation of devices, detailed
|
|
||||||
* on this page.
|
|
||||||
*
|
|
||||||
* \section enrolling Enrolling
|
|
||||||
* Enrolling is represented within libfprint as a multi-stage process. This
|
|
||||||
* slightly complicates things for application developers, but is required
|
|
||||||
* for a smooth process.
|
|
||||||
*
|
|
||||||
* Some devices require the user to scan their finger multiple times in
|
|
||||||
* order to complete the enrollment process. libfprint must return control
|
|
||||||
* to your application inbetween each scan in order for your application to
|
|
||||||
* instruct the user to swipe their finger again. Each scan is referred to
|
|
||||||
* as a stage, so a device that requires 3 scans for enrollment corresponds
|
|
||||||
* to you running 3 enrollment stages using libfprint.
|
|
||||||
*
|
|
||||||
* The fp_dev_get_nr_enroll_stages() function can be used to find out how
|
|
||||||
* many enroll stages are needed.
|
|
||||||
*
|
|
||||||
* In order to complete an enroll stage, you call an enroll function such
|
|
||||||
* as fp_enroll_finger(). The return of this function does not necessarily
|
|
||||||
* indicate that a stage has completed though, as the user may not have
|
|
||||||
* produced a good enough scan. Each stage may have to be retried several
|
|
||||||
* times.
|
|
||||||
*
|
|
||||||
* The exact semantics of the enroll functions are described in the
|
|
||||||
* fp_enroll_finger() documentation. You should pay careful attention to the
|
|
||||||
* details.
|
|
||||||
*
|
|
||||||
* \section imaging Imaging
|
|
||||||
* libfprint provides you with some ways to retrieve images of scanned
|
|
||||||
* fingers, such as the fp_dev_img_capture() function, or some enroll/verify
|
|
||||||
* function variants which provide images. You may wish to do something with
|
|
||||||
* such images in your application.
|
|
||||||
*
|
|
||||||
* However, you must be aware that not all hardware supported by libfprint
|
|
||||||
* operates like this. Most hardware does operate simply by sending
|
|
||||||
* fingerprint images to the host computer for further processing, but some
|
|
||||||
* devices do all fingerprint processing in hardware and do not present images
|
|
||||||
* to the host computer.
|
|
||||||
*
|
|
||||||
* You can use fp_dev_supports_imaging() to see if image capture is possible
|
|
||||||
* on a particular device. Your application must be able to cope with the
|
|
||||||
* fact that libfprint does support regular operations (e.g. enrolling and
|
|
||||||
* verification) on some devices which do not provide images.
|
|
||||||
*
|
|
||||||
* \section devtype Devtypes
|
|
||||||
* Internally, the \ref drv "driver" behind a device assigns a 32-bit
|
|
||||||
* <em>devtype</em> identifier to the device. This cannot be used as a unique
|
|
||||||
* ID for a specific device as many devices under the same range may share
|
|
||||||
* the same devtype. The devtype may even be 0 in all cases.
|
|
||||||
*
|
|
||||||
* The only reason you may be interested in retrieving the devtype for a
|
|
||||||
* device is for the purpose of checking if some print data is compatible
|
|
||||||
* with a device. libfprint uses the devtype as one way of checking that the
|
|
||||||
* print you are verifying is compatible with the device in question - the
|
|
||||||
* devtypes must be equal. This effectively allows drivers to support more
|
|
||||||
* than one type of device where the data from each one is not compatible with
|
|
||||||
* the other. Note that libfprint does provide you with helper functions to
|
|
||||||
* determine whether a print is compatible with a device, so under most
|
|
||||||
* circumstances, you don't have to worry about devtypes at all.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** @defgroup dscv_dev Device discovery
|
|
||||||
* These functions allow you to scan the system for supported fingerprint
|
|
||||||
* scanning hardware. This is your starting point when integrating libfprint
|
|
||||||
* into your software.
|
|
||||||
*
|
|
||||||
* When you've identified a discovered device that you would like to control,
|
|
||||||
* you can open it with fp_dev_open(). Note that discovered devices may no
|
|
||||||
* longer be available at the time when you want to open them, for example
|
|
||||||
* the user may have unplugged the device.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** @defgroup drv Driver operations
|
|
||||||
* Internally, libfprint is abstracted into various drivers to communicate
|
|
||||||
* with the different types of supported fingerprint readers. libfprint works
|
|
||||||
* hard so that you don't have to care about these internal abstractions,
|
|
||||||
* however there are some situations where you may be interested in a little
|
|
||||||
* behind-the-scenes driver info.
|
|
||||||
*
|
|
||||||
* You can obtain the driver for a device using fp_dev_get_driver(), which
|
|
||||||
* you can pass to the functions documented on this page.
|
|
||||||
*
|
|
||||||
* \section driver_id Driver IDs
|
|
||||||
* Each driver is assigned a unique ID by the project maintainer. These
|
|
||||||
* assignments are
|
|
||||||
* <a href="http://www.reactivated.net/fprint/Driver_ID_assignments">
|
|
||||||
* documented on the wiki</a> and will never change.
|
|
||||||
*
|
|
||||||
* The only reason you may be interested in retrieving the driver ID for a
|
|
||||||
* driver is for the purpose of checking if some print data is compatible
|
|
||||||
* with a device. libfprint uses the driver ID as one way of checking that
|
|
||||||
* the print you are trying to verify is compatible with the device in
|
|
||||||
* question - it ensures that enrollment data from one driver is never fed to
|
|
||||||
* another. Note that libfprint does provide you with helper functions to
|
|
||||||
* determine whether a print is compatible with a device, so under most
|
|
||||||
* circumstances, you don't have to worry about driver IDs at all.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static GSList *registered_drivers = NULL;
|
|
||||||
|
|
||||||
void fpi_log(enum fpi_log_level level, const char *component,
|
|
||||||
const char *function, const char *format, ...)
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
FILE *stream = stdout;
|
|
||||||
const char *prefix;
|
|
||||||
|
|
||||||
#ifndef ENABLE_DEBUG_LOGGING
|
|
||||||
if (!log_level)
|
|
||||||
return;
|
|
||||||
if (level == FPRINT_LOG_LEVEL_WARNING && log_level < 2)
|
|
||||||
return;
|
|
||||||
if (level == FPRINT_LOG_LEVEL_INFO && log_level < 3)
|
|
||||||
return;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
switch (level) {
|
|
||||||
case FPRINT_LOG_LEVEL_INFO:
|
|
||||||
prefix = "info";
|
|
||||||
break;
|
|
||||||
case FPRINT_LOG_LEVEL_WARNING:
|
|
||||||
stream = stderr;
|
|
||||||
prefix = "warning";
|
|
||||||
break;
|
|
||||||
case FPRINT_LOG_LEVEL_ERROR:
|
|
||||||
stream = stderr;
|
|
||||||
prefix = "error";
|
|
||||||
break;
|
|
||||||
case FPRINT_LOG_LEVEL_DEBUG:
|
|
||||||
stream = stderr;
|
|
||||||
prefix = "debug";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
stream = stderr;
|
|
||||||
prefix = "unknown";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(stream, "%s:%s [%s] ", component ? component : "fp", prefix,
|
|
||||||
function);
|
|
||||||
|
|
||||||
va_start (args, format);
|
|
||||||
vfprintf(stream, format, args);
|
|
||||||
va_end (args);
|
|
||||||
|
|
||||||
fprintf(stream, "\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void register_driver(struct fp_driver *drv)
|
|
||||||
{
|
|
||||||
if (drv->id == 0) {
|
|
||||||
fp_err("not registering driver %s: driver ID is 0", drv->name);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
registered_drivers = g_slist_prepend(registered_drivers, (gpointer) drv);
|
|
||||||
fp_dbg("registered driver %s", drv->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct fp_driver * const primitive_drivers[] = {
|
|
||||||
#ifdef ENABLE_UPEKTS
|
|
||||||
&upekts_driver,
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_UPEKE2
|
|
||||||
&upeke2_driver,
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct fp_img_driver * const img_drivers[] = {
|
|
||||||
#ifdef ENABLE_AES3500
|
|
||||||
&aes3500_driver,
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_AES4000
|
|
||||||
&aes4000_driver,
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_AES2501
|
|
||||||
&aes2501_driver,
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_AES2550
|
|
||||||
&aes2550_driver,
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_URU4000
|
|
||||||
&uru4000_driver,
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_VCOM5S
|
|
||||||
&vcom5s_driver,
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_UPEKSONLY
|
|
||||||
&upeksonly_driver,
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef ENABLE_AES1610
|
|
||||||
&aes1610_driver,
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_AES1660
|
|
||||||
&aes1660_driver,
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_AES2660
|
|
||||||
&aes2660_driver,
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_VFS101
|
|
||||||
&vfs101_driver,
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_VFS301
|
|
||||||
&vfs301_driver,
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_VFS5011
|
|
||||||
&vfs5011_driver,
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_UPEKTC
|
|
||||||
&upektc_driver,
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_UPEKTC_IMG
|
|
||||||
&upektc_img_driver,
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_ETES603
|
|
||||||
&etes603_driver,
|
|
||||||
#endif
|
|
||||||
/*#ifdef ENABLE_FDU2000
|
|
||||||
&fdu2000_driver,
|
|
||||||
#endif
|
|
||||||
*/
|
|
||||||
};
|
|
||||||
|
|
||||||
static void register_drivers(void)
|
|
||||||
{
|
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
for (i = 0; i < G_N_ELEMENTS(primitive_drivers); i++)
|
|
||||||
register_driver(primitive_drivers[i]);
|
|
||||||
|
|
||||||
for (i = 0; i < G_N_ELEMENTS(img_drivers); i++) {
|
|
||||||
struct fp_img_driver *imgdriver = img_drivers[i];
|
|
||||||
fpi_img_driver_setup(imgdriver);
|
|
||||||
register_driver(&imgdriver->driver);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
API_EXPORTED struct fp_driver **fprint_get_drivers (void)
|
|
||||||
{
|
|
||||||
GPtrArray *array;
|
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
array = g_ptr_array_new ();
|
|
||||||
for (i = 0; i < G_N_ELEMENTS(primitive_drivers); i++)
|
|
||||||
g_ptr_array_add (array, primitive_drivers[i]);
|
|
||||||
|
|
||||||
for (i = 0; i < G_N_ELEMENTS(img_drivers); i++)
|
|
||||||
g_ptr_array_add (array, &(img_drivers[i]->driver));
|
|
||||||
|
|
||||||
/* Add a null item terminating the array */
|
|
||||||
g_ptr_array_add (array, NULL);
|
|
||||||
|
|
||||||
return (struct fp_driver **) g_ptr_array_free (array, FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct fp_driver *find_supporting_driver(libusb_device *udev,
|
|
||||||
const struct usb_id **usb_id, uint32_t *devtype)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
GSList *elem = registered_drivers;
|
|
||||||
struct libusb_device_descriptor dsc;
|
|
||||||
|
|
||||||
const struct usb_id *best_usb_id;
|
|
||||||
struct fp_driver *best_drv;
|
|
||||||
uint32_t best_devtype;
|
|
||||||
int drv_score = 0;
|
|
||||||
|
|
||||||
ret = libusb_get_device_descriptor(udev, &dsc);
|
|
||||||
if (ret < 0) {
|
|
||||||
fp_err("Failed to get device descriptor");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
best_drv = NULL;
|
|
||||||
best_devtype = 0;
|
|
||||||
|
|
||||||
do {
|
|
||||||
struct fp_driver *drv = elem->data;
|
|
||||||
uint32_t type = 0;
|
|
||||||
const struct usb_id *id;
|
|
||||||
|
|
||||||
for (id = drv->id_table; id->vendor; id++) {
|
|
||||||
if (dsc.idVendor == id->vendor && dsc.idProduct == id->product) {
|
|
||||||
if (drv->discover) {
|
|
||||||
int r = drv->discover(&dsc, &type);
|
|
||||||
if (r < 0)
|
|
||||||
fp_err("%s discover failed, code %d", drv->name, r);
|
|
||||||
if (r <= 0)
|
|
||||||
continue;
|
|
||||||
/* Has a discover function, and matched our device */
|
|
||||||
drv_score = 100;
|
|
||||||
} else {
|
|
||||||
/* Already got a driver as good */
|
|
||||||
if (drv_score >= 50)
|
|
||||||
continue;
|
|
||||||
drv_score = 50;
|
|
||||||
}
|
|
||||||
fp_dbg("driver %s supports USB device %04x:%04x",
|
|
||||||
drv->name, id->vendor, id->product);
|
|
||||||
best_usb_id = id;
|
|
||||||
best_drv = drv;
|
|
||||||
best_devtype = type;
|
|
||||||
|
|
||||||
/* We found the best possible driver */
|
|
||||||
if (drv_score == 100)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while ((elem = g_slist_next(elem)));
|
|
||||||
|
|
||||||
if (best_drv != NULL) {
|
|
||||||
fp_dbg("selected driver %s supports USB device %04x:%04x",
|
|
||||||
best_drv->name, dsc.idVendor, dsc.idProduct);
|
|
||||||
*devtype = best_devtype;
|
|
||||||
*usb_id = best_usb_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
return best_drv;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct fp_dscv_dev *discover_dev(libusb_device *udev)
|
|
||||||
{
|
|
||||||
const struct usb_id *usb_id;
|
|
||||||
struct fp_driver *drv;
|
|
||||||
struct fp_dscv_dev *ddev;
|
|
||||||
uint32_t devtype;
|
|
||||||
|
|
||||||
drv = find_supporting_driver(udev, &usb_id, &devtype);
|
|
||||||
|
|
||||||
if (!drv)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
ddev = g_malloc0(sizeof(*ddev));
|
|
||||||
ddev->drv = drv;
|
|
||||||
ddev->udev = udev;
|
|
||||||
ddev->driver_data = usb_id->driver_data;
|
|
||||||
ddev->devtype = devtype;
|
|
||||||
return ddev;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup dscv_dev
|
|
||||||
* Scans the system and returns a list of discovered devices. This is your
|
|
||||||
* entry point into finding a fingerprint reader to operate.
|
|
||||||
* \returns a NULL-terminated list of discovered devices. Must be freed with
|
|
||||||
* fp_dscv_devs_free() after use.
|
|
||||||
*/
|
|
||||||
API_EXPORTED struct fp_dscv_dev **fp_discover_devs(void)
|
|
||||||
{
|
|
||||||
GSList *tmplist = NULL;
|
|
||||||
struct fp_dscv_dev **list;
|
|
||||||
libusb_device *udev;
|
|
||||||
libusb_device **devs;
|
|
||||||
int dscv_count = 0;
|
|
||||||
int r;
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
if (registered_drivers == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
r = libusb_get_device_list(fpi_usb_ctx, &devs);
|
|
||||||
if (r < 0) {
|
|
||||||
fp_err("couldn't enumerate USB devices, error %d", r);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check each device against each driver, temporarily storing successfully
|
|
||||||
* discovered devices in a GSList.
|
|
||||||
*
|
|
||||||
* Quite inefficient but excusable as we'll only be dealing with small
|
|
||||||
* sets of drivers against small sets of USB devices */
|
|
||||||
while ((udev = devs[i++]) != NULL) {
|
|
||||||
struct fp_dscv_dev *ddev = discover_dev(udev);
|
|
||||||
if (!ddev)
|
|
||||||
continue;
|
|
||||||
tmplist = g_slist_prepend(tmplist, (gpointer) ddev);
|
|
||||||
dscv_count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Convert our temporary GSList into a standard NULL-terminated pointer
|
|
||||||
* array. */
|
|
||||||
list = g_malloc(sizeof(*list) * (dscv_count + 1));
|
|
||||||
if (dscv_count > 0) {
|
|
||||||
GSList *elem = tmplist;
|
|
||||||
i = 0;
|
|
||||||
do {
|
|
||||||
list[i++] = elem->data;
|
|
||||||
} while ((elem = g_slist_next(elem)));
|
|
||||||
}
|
|
||||||
list[dscv_count] = NULL; /* NULL-terminate */
|
|
||||||
|
|
||||||
g_slist_free(tmplist);
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup dscv_dev
|
|
||||||
* Free a list of discovered devices. This function destroys the list and all
|
|
||||||
* discovered devices that it included, so make sure you have opened your
|
|
||||||
* discovered device <b>before</b> freeing the list.
|
|
||||||
* \param devs the list of discovered devices. If NULL, function simply
|
|
||||||
* returns.
|
|
||||||
*/
|
|
||||||
API_EXPORTED void fp_dscv_devs_free(struct fp_dscv_dev **devs)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
if (!devs)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (i = 0; devs[i]; i++)
|
|
||||||
g_free(devs[i]);
|
|
||||||
g_free(devs);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup dscv_dev
|
|
||||||
* Gets the \ref drv "driver" for a discovered device.
|
|
||||||
* \param dev the discovered device
|
|
||||||
* \returns the driver backing the device
|
|
||||||
*/
|
|
||||||
API_EXPORTED struct fp_driver *fp_dscv_dev_get_driver(struct fp_dscv_dev *dev)
|
|
||||||
{
|
|
||||||
return dev->drv;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup dscv_dev
|
|
||||||
* Gets the \ref devtype "devtype" for a discovered device.
|
|
||||||
* \param dev the discovered device
|
|
||||||
* \returns the devtype of the device
|
|
||||||
*/
|
|
||||||
API_EXPORTED uint32_t fp_dscv_dev_get_devtype(struct fp_dscv_dev *dev)
|
|
||||||
{
|
|
||||||
return dev->devtype;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum fp_print_data_type fpi_driver_get_data_type(struct fp_driver *drv)
|
|
||||||
{
|
|
||||||
switch (drv->type) {
|
|
||||||
case DRIVER_PRIMITIVE:
|
|
||||||
return PRINT_DATA_RAW;
|
|
||||||
case DRIVER_IMAGING:
|
|
||||||
return PRINT_DATA_NBIS_MINUTIAE;
|
|
||||||
default:
|
|
||||||
fp_err("unrecognised drv type %d", drv->type);
|
|
||||||
return PRINT_DATA_RAW;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup dscv_dev
|
|
||||||
* Determines if a specific \ref print_data "stored print" appears to be
|
|
||||||
* compatible with a discovered device.
|
|
||||||
* \param dev the discovered device
|
|
||||||
* \param data the print for compatibility checking
|
|
||||||
* \returns 1 if the print is compatible with the device, 0 otherwise
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_dscv_dev_supports_print_data(struct fp_dscv_dev *dev,
|
|
||||||
struct fp_print_data *data)
|
|
||||||
{
|
|
||||||
return fpi_print_data_compatible(dev->drv->id, dev->devtype,
|
|
||||||
fpi_driver_get_data_type(dev->drv), data->driver_id, data->devtype,
|
|
||||||
data->type);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup dscv_dev
|
|
||||||
* Determines if a specific \ref dscv_print "discovered print" appears to be
|
|
||||||
* compatible with a discovered device.
|
|
||||||
* \param dev the discovered device
|
|
||||||
* \param data the discovered print for compatibility checking
|
|
||||||
* \returns 1 if the print is compatible with the device, 0 otherwise
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_dscv_dev_supports_dscv_print(struct fp_dscv_dev *dev,
|
|
||||||
struct fp_dscv_print *data)
|
|
||||||
{
|
|
||||||
return fpi_print_data_compatible(dev->drv->id, dev->devtype, 0,
|
|
||||||
data->driver_id, data->devtype, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup dscv_dev
|
|
||||||
* Searches a list of discovered devices for a device that appears to be
|
|
||||||
* compatible with a \ref print_data "stored print".
|
|
||||||
* \param devs a list of discovered devices
|
|
||||||
* \param data the print under inspection
|
|
||||||
* \returns the first discovered device that appears to support the print, or
|
|
||||||
* NULL if no apparently compatible devices could be found
|
|
||||||
*/
|
|
||||||
API_EXPORTED struct fp_dscv_dev *fp_dscv_dev_for_print_data(struct fp_dscv_dev **devs,
|
|
||||||
struct fp_print_data *data)
|
|
||||||
{
|
|
||||||
struct fp_dscv_dev *ddev;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; (ddev = devs[i]); i++)
|
|
||||||
if (fp_dscv_dev_supports_print_data(ddev, data))
|
|
||||||
return ddev;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup dscv_dev
|
|
||||||
* Searches a list of discovered devices for a device that appears to be
|
|
||||||
* compatible with a \ref dscv_print "discovered print".
|
|
||||||
* \param devs a list of discovered devices
|
|
||||||
* \param print the print under inspection
|
|
||||||
* \returns the first discovered device that appears to support the print, or
|
|
||||||
* NULL if no apparently compatible devices could be found
|
|
||||||
*/
|
|
||||||
API_EXPORTED struct fp_dscv_dev *fp_dscv_dev_for_dscv_print(struct fp_dscv_dev **devs,
|
|
||||||
struct fp_dscv_print *print)
|
|
||||||
{
|
|
||||||
struct fp_dscv_dev *ddev;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; (ddev = devs[i]); i++)
|
|
||||||
if (fp_dscv_dev_supports_dscv_print(ddev, print))
|
|
||||||
return ddev;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup dev
|
|
||||||
* Get the \ref drv "driver" for a fingerprint device.
|
|
||||||
* \param dev the device
|
|
||||||
* \returns the driver controlling the device
|
|
||||||
*/
|
|
||||||
API_EXPORTED struct fp_driver *fp_dev_get_driver(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
return dev->drv;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup dev
|
|
||||||
* Gets the number of \ref enrolling "enroll stages" required to enroll a
|
|
||||||
* fingerprint with the device.
|
|
||||||
* \param dev the device
|
|
||||||
* \returns the number of enroll stages
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_dev_get_nr_enroll_stages(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
return dev->nr_enroll_stages;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup dev
|
|
||||||
* Gets the \ref devtype "devtype" for a device.
|
|
||||||
* \param dev the device
|
|
||||||
* \returns the devtype
|
|
||||||
*/
|
|
||||||
API_EXPORTED uint32_t fp_dev_get_devtype(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
return dev->devtype;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup dev
|
|
||||||
* Determines if a stored print is compatible with a certain device.
|
|
||||||
* \param dev the device
|
|
||||||
* \param data the stored print
|
|
||||||
* \returns 1 if the print is compatible with the device, 0 if not
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_dev_supports_print_data(struct fp_dev *dev,
|
|
||||||
struct fp_print_data *data)
|
|
||||||
{
|
|
||||||
return fpi_print_data_compatible(dev->drv->id, dev->devtype,
|
|
||||||
fpi_driver_get_data_type(dev->drv), data->driver_id, data->devtype,
|
|
||||||
data->type);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup dev
|
|
||||||
* Determines if a \ref dscv_print "discovered print" appears to be compatible
|
|
||||||
* with a certain device.
|
|
||||||
* \param dev the device
|
|
||||||
* \param data the discovered print
|
|
||||||
* \returns 1 if the print is compatible with the device, 0 if not
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_dev_supports_dscv_print(struct fp_dev *dev,
|
|
||||||
struct fp_dscv_print *data)
|
|
||||||
{
|
|
||||||
return fpi_print_data_compatible(dev->drv->id, dev->devtype,
|
|
||||||
0, data->driver_id, data->devtype, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup drv
|
|
||||||
* Retrieves the name of the driver. For example: "upekts"
|
|
||||||
* \param drv the driver
|
|
||||||
* \returns the driver name. Must not be modified or freed.
|
|
||||||
*/
|
|
||||||
API_EXPORTED const char *fp_driver_get_name(struct fp_driver *drv)
|
|
||||||
{
|
|
||||||
return drv->name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup drv
|
|
||||||
* Retrieves a descriptive name of the driver. For example: "UPEK TouchStrip"
|
|
||||||
* \param drv the driver
|
|
||||||
* \returns the descriptive name. Must not be modified or freed.
|
|
||||||
*/
|
|
||||||
API_EXPORTED const char *fp_driver_get_full_name(struct fp_driver *drv)
|
|
||||||
{
|
|
||||||
return drv->full_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup drv
|
|
||||||
* Retrieves the driver ID code for a driver.
|
|
||||||
* \param drv the driver
|
|
||||||
* \returns the driver ID
|
|
||||||
*/
|
|
||||||
API_EXPORTED uint16_t fp_driver_get_driver_id(struct fp_driver *drv)
|
|
||||||
{
|
|
||||||
return drv->id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup drv
|
|
||||||
* Retrieves the scan type for the devices associated with the driver.
|
|
||||||
* \param drv the driver
|
|
||||||
* \returns the scan type
|
|
||||||
*/
|
|
||||||
API_EXPORTED enum fp_scan_type fp_driver_get_scan_type(struct fp_driver *drv)
|
|
||||||
{
|
|
||||||
return drv->scan_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct fp_img_dev *dev_to_img_dev(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
if (dev->drv->type != DRIVER_IMAGING)
|
|
||||||
return NULL;
|
|
||||||
return dev->priv;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup dev
|
|
||||||
* Determines if a device has imaging capabilities. If a device has imaging
|
|
||||||
* capabilities you are able to perform imaging operations such as retrieving
|
|
||||||
* scan images using fp_dev_img_capture(). However, not all devices are
|
|
||||||
* imaging devices - some do all processing in hardware. This function will
|
|
||||||
* indicate which class a device in question falls into.
|
|
||||||
* \param dev the fingerprint device
|
|
||||||
* \returns 1 if the device is an imaging device, 0 if the device does not
|
|
||||||
* provide images to the host computer
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_dev_supports_imaging(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
return dev->drv->capture_start != NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup dev
|
|
||||||
* Determines if a device is capable of \ref identification "identification"
|
|
||||||
* through fp_identify_finger() and similar. Not all devices support this
|
|
||||||
* functionality.
|
|
||||||
* \param dev the fingerprint device
|
|
||||||
* \returns 1 if the device is capable of identification, 0 otherwise.
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_dev_supports_identification(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
return dev->drv->identify_start != NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup dev
|
|
||||||
* Gets the expected width of images that will be captured from the device.
|
|
||||||
* This function will return -1 for devices that are not
|
|
||||||
* \ref imaging "imaging devices". If the width of images from this device
|
|
||||||
* can vary, 0 will be returned.
|
|
||||||
* \param dev the device
|
|
||||||
* \returns the expected image width, or 0 for variable, or -1 for non-imaging
|
|
||||||
* devices.
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_dev_get_img_width(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
struct fp_img_dev *imgdev = dev_to_img_dev(dev);
|
|
||||||
if (!imgdev) {
|
|
||||||
fp_dbg("get image width for non-imaging device");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return fpi_imgdev_get_img_width(imgdev);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup dev
|
|
||||||
* Gets the expected height of images that will be captured from the device.
|
|
||||||
* This function will return -1 for devices that are not
|
|
||||||
* \ref imaging "imaging devices". If the height of images from this device
|
|
||||||
* can vary, 0 will be returned.
|
|
||||||
* \param dev the device
|
|
||||||
* \returns the expected image height, or 0 for variable, or -1 for non-imaging
|
|
||||||
* devices.
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_dev_get_img_height(struct fp_dev *dev)
|
|
||||||
{
|
|
||||||
struct fp_img_dev *imgdev = dev_to_img_dev(dev);
|
|
||||||
if (!imgdev) {
|
|
||||||
fp_dbg("get image height for non-imaging device");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return fpi_imgdev_get_img_height(imgdev);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup core
|
|
||||||
* Set message verbosity.
|
|
||||||
* - Level 0: no messages ever printed by the library (default)
|
|
||||||
* - Level 1: error messages are printed to stderr
|
|
||||||
* - Level 2: warning and error messages are printed to stderr
|
|
||||||
* - Level 3: informational messages are printed to stdout, warning and error
|
|
||||||
* messages are printed to stderr
|
|
||||||
*
|
|
||||||
* The default level is 0, which means no messages are ever printed. If you
|
|
||||||
* choose to increase the message verbosity level, ensure that your
|
|
||||||
* application does not close the stdout/stderr file descriptors.
|
|
||||||
*
|
|
||||||
* You are advised to set level 3. libfprint is conservative with its message
|
|
||||||
* logging and most of the time, will only log messages that explain error
|
|
||||||
* conditions and other oddities. This will help you debug your software.
|
|
||||||
*
|
|
||||||
* If the LIBFPRINT_DEBUG environment variable was set when libfprint was
|
|
||||||
* initialized, this function does nothing: the message verbosity is fixed
|
|
||||||
* to the value in the environment variable.
|
|
||||||
*
|
|
||||||
* If libfprint was compiled without any message logging, this function does
|
|
||||||
* nothing: you'll never get any messages.
|
|
||||||
*
|
|
||||||
* If libfprint was compiled with verbose debug message logging, this function
|
|
||||||
* does nothing: you'll always get messages from all levels.
|
|
||||||
*
|
|
||||||
* \param ctx the context to operate on, or NULL for the default context
|
|
||||||
* \param level debug level to set
|
|
||||||
*/
|
|
||||||
API_EXPORTED void fp_set_debug(int level)
|
|
||||||
{
|
|
||||||
if (log_level_fixed)
|
|
||||||
return;
|
|
||||||
|
|
||||||
log_level = level;
|
|
||||||
libusb_set_debug(fpi_usb_ctx, level);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup core
|
|
||||||
* Initialise libfprint. This function must be called before you attempt to
|
|
||||||
* use the library in any way.
|
|
||||||
* \return 0 on success, non-zero on error.
|
|
||||||
*/
|
|
||||||
API_EXPORTED int fp_init(void)
|
|
||||||
{
|
|
||||||
char *dbg = getenv("LIBFPRINT_DEBUG");
|
|
||||||
int r;
|
|
||||||
fp_dbg("");
|
|
||||||
|
|
||||||
r = libusb_init(&fpi_usb_ctx);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
if (dbg) {
|
|
||||||
log_level = atoi(dbg);
|
|
||||||
if (log_level) {
|
|
||||||
log_level_fixed = 1;
|
|
||||||
libusb_set_debug(fpi_usb_ctx, log_level);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
register_drivers();
|
|
||||||
fpi_poll_init();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \ingroup core
|
|
||||||
* Deinitialise libfprint. This function should be called during your program
|
|
||||||
* exit sequence. You must not use any libfprint functions after calling this
|
|
||||||
* function, unless you call fp_init() again.
|
|
||||||
*/
|
|
||||||
API_EXPORTED void fp_exit(void)
|
|
||||||
{
|
|
||||||
fp_dbg("");
|
|
||||||
|
|
||||||
if (opened_devices) {
|
|
||||||
GSList *copy = g_slist_copy(opened_devices);
|
|
||||||
GSList *elem = copy;
|
|
||||||
fp_dbg("naughty app left devices open on exit!");
|
|
||||||
|
|
||||||
do
|
|
||||||
fp_dev_close((struct fp_dev *) elem->data);
|
|
||||||
while ((elem = g_slist_next(elem)));
|
|
||||||
|
|
||||||
g_slist_free(copy);
|
|
||||||
g_slist_free(opened_devices);
|
|
||||||
opened_devices = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
fpi_data_exit();
|
|
||||||
fpi_poll_exit();
|
|
||||||
g_slist_free(registered_drivers);
|
|
||||||
registered_drivers = NULL;
|
|
||||||
libusb_exit(fpi_usb_ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -25,15 +25,8 @@
|
|||||||
|
|
||||||
#define FP_COMPONENT "aes1610"
|
#define FP_COMPONENT "aes1610"
|
||||||
|
|
||||||
#include <errno.h>
|
#include "drivers_api.h"
|
||||||
#include <string.h>
|
#include "aeslib.h"
|
||||||
|
|
||||||
#include <libusb.h>
|
|
||||||
|
|
||||||
#include <aeslib.h>
|
|
||||||
#include <fp_internal.h>
|
|
||||||
|
|
||||||
#include "driver_ids.h"
|
|
||||||
|
|
||||||
static void start_capture(struct fp_img_dev *dev);
|
static void start_capture(struct fp_img_dev *dev);
|
||||||
static void complete_deactivation(struct fp_img_dev *dev);
|
static void complete_deactivation(struct fp_img_dev *dev);
|
||||||
@@ -51,6 +44,9 @@ static int adjust_gain(unsigned char *buffer, int status);
|
|||||||
|
|
||||||
#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,6 +62,7 @@ static int adjust_gain(unsigned char *buffer, int status);
|
|||||||
#define FRAME_WIDTH 128
|
#define FRAME_WIDTH 128
|
||||||
#define FRAME_HEIGHT 8
|
#define FRAME_HEIGHT 8
|
||||||
#define FRAME_SIZE (FRAME_WIDTH * FRAME_HEIGHT)
|
#define FRAME_SIZE (FRAME_WIDTH * FRAME_HEIGHT)
|
||||||
|
#define IMAGE_WIDTH (FRAME_WIDTH + (FRAME_WIDTH / 2))
|
||||||
/* maximum number of frames to read during a scan */
|
/* maximum number of frames to read during a scan */
|
||||||
/* FIXME reduce substantially */
|
/* FIXME reduce substantially */
|
||||||
#define MAX_FRAMES 350
|
#define MAX_FRAMES 350
|
||||||
@@ -80,6 +77,13 @@ struct aes1610_dev {
|
|||||||
uint8_t blanks_count;
|
uint8_t blanks_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct fpi_frame_asmbl_ctx assembling_ctx = {
|
||||||
|
.frame_width = FRAME_WIDTH,
|
||||||
|
.frame_height = FRAME_HEIGHT,
|
||||||
|
.image_width = IMAGE_WIDTH,
|
||||||
|
.get_pixel = aes_get_pixel,
|
||||||
|
};
|
||||||
|
|
||||||
typedef void (*aes1610_read_regs_cb)(struct fp_img_dev *dev, int status,
|
typedef void (*aes1610_read_regs_cb)(struct fp_img_dev *dev, int status,
|
||||||
unsigned char *regs, void *user_data);
|
unsigned char *regs, void *user_data);
|
||||||
|
|
||||||
@@ -100,12 +104,12 @@ static void stub_capture_stop_cb(struct fp_img_dev *dev, int result, void *user_
|
|||||||
/* check that read succeeded but ignore all data */
|
/* check that read succeeded but ignore all data */
|
||||||
static void generic_ignore_data_cb(struct libusb_transfer *transfer)
|
static void generic_ignore_data_cb(struct libusb_transfer *transfer)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
|
|
||||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
|
if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
else if (transfer->length != transfer->actual_length)
|
else if (transfer->length != transfer->actual_length)
|
||||||
fpi_ssm_mark_aborted(ssm, -EPROTO);
|
fpi_ssm_mark_failed(ssm, -EPROTO);
|
||||||
else
|
else
|
||||||
fpi_ssm_next_state(ssm);
|
fpi_ssm_next_state(ssm);
|
||||||
|
|
||||||
@@ -116,35 +120,30 @@ static void generic_ignore_data_cb(struct libusb_transfer *transfer)
|
|||||||
static void generic_write_regv_cb(struct fp_img_dev *dev, int result,
|
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;
|
fpi_ssm *ssm = user_data;
|
||||||
if (result == 0)
|
if (result == 0)
|
||||||
fpi_ssm_next_state(ssm);
|
fpi_ssm_next_state(ssm);
|
||||||
else
|
else
|
||||||
fpi_ssm_mark_aborted(ssm, result);
|
fpi_ssm_mark_failed(ssm, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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(fpi_ssm *ssm, struct fp_dev *dev, size_t bytes)
|
||||||
{
|
{
|
||||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||||
unsigned char *data;
|
unsigned char *data;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (!transfer) {
|
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
data = g_malloc(bytes);
|
data = g_malloc(bytes);
|
||||||
libusb_fill_bulk_transfer(transfer, ssm->dev->udev, EP_IN, data, bytes,
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(dev), EP_IN, data, bytes,
|
||||||
generic_ignore_data_cb, ssm, BULK_TIMEOUT);
|
generic_ignore_data_cb, ssm, BULK_TIMEOUT);
|
||||||
|
|
||||||
r = libusb_submit_transfer(transfer);
|
r = libusb_submit_transfer(transfer);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
g_free(data);
|
g_free(data);
|
||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
fpi_ssm_mark_aborted(ssm, r);
|
fpi_ssm_mark_failed(ssm, r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,14 +222,9 @@ static void finger_det_reqs_cb(struct fp_img_dev *dev, int result, void *user_da
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
transfer = libusb_alloc_transfer(0);
|
transfer = fpi_usb_alloc();
|
||||||
if (!transfer) {
|
data = g_malloc(FINGER_DETECTION_LEN);
|
||||||
fpi_imgdev_session_error(dev, -ENOMEM);
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, data, FINGER_DETECTION_LEN,
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
data = g_malloc(19);
|
|
||||||
libusb_fill_bulk_transfer(transfer, dev->udev, EP_IN, data, 19,
|
|
||||||
finger_det_data_cb, dev, BULK_TIMEOUT);
|
finger_det_data_cb, dev, BULK_TIMEOUT);
|
||||||
|
|
||||||
r = libusb_submit_transfer(transfer);
|
r = libusb_submit_transfer(transfer);
|
||||||
@@ -244,7 +238,7 @@ static void finger_det_reqs_cb(struct fp_img_dev *dev, int result, void *user_da
|
|||||||
|
|
||||||
static void start_finger_detection(struct fp_img_dev *dev)
|
static void start_finger_detection(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct aes1610_dev *aesdev = dev->priv;
|
struct aes1610_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
|
||||||
if (aesdev->deactivating) {
|
if (aesdev->deactivating) {
|
||||||
complete_deactivation(dev);
|
complete_deactivation(dev);
|
||||||
@@ -404,13 +398,13 @@ static unsigned char list_BE_values[10] = {
|
|||||||
/*
|
/*
|
||||||
* The different possible values for 0xBD register */
|
* The different possible values for 0xBD register */
|
||||||
static unsigned char list_BD_values[10] = {
|
static unsigned char list_BD_values[10] = {
|
||||||
0x48, 0x4B, 0x4F, 0x52, 0x57, 0x59, 0x5B
|
0x28, 0x2b, 0x30, 0x3b, 0x45, 0x49, 0x4B
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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)
|
||||||
{
|
{
|
||||||
@@ -418,32 +412,32 @@ static int adjust_gain(unsigned char *buffer, int status)
|
|||||||
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 = 0x5B;
|
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 = 0x4F;
|
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 = 0x4B;
|
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;
|
||||||
strip_scan_reqs[3].value = 0x48;
|
strip_scan_reqs[3].value = 0x28;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now copy this values in capture_reqs
|
// Now copy this values in capture_reqs
|
||||||
@@ -540,7 +534,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,17 +548,17 @@ enum capture_states {
|
|||||||
static void capture_read_strip_cb(struct libusb_transfer *transfer)
|
static void capture_read_strip_cb(struct libusb_transfer *transfer)
|
||||||
{
|
{
|
||||||
unsigned char *stripdata;
|
unsigned char *stripdata;
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
||||||
struct aes1610_dev *aesdev = dev->priv;
|
struct aes1610_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
unsigned char *data = transfer->buffer;
|
unsigned char *data = transfer->buffer;
|
||||||
int sum, i;
|
int sum, i;
|
||||||
|
|
||||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
goto out;
|
goto out;
|
||||||
} else if (transfer->length != transfer->actual_length) {
|
} else if (transfer->length != transfer->actual_length) {
|
||||||
fpi_ssm_mark_aborted(ssm, -EPROTO);
|
fpi_ssm_mark_failed(ssm, -EPROTO);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -579,16 +573,19 @@ static void capture_read_strip_cb(struct libusb_transfer *transfer)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (sum > 0) {
|
if (sum > 0) {
|
||||||
/* FIXME: would preallocating strip buffers be a decent optimization? */
|
/* FIXME: would preallocating strip buffers be a decent optimization? */
|
||||||
stripdata = g_malloc(128 * 4);
|
struct fpi_frame *stripe = g_malloc(FRAME_WIDTH * (FRAME_HEIGHT / 2) + sizeof(struct fpi_frame));
|
||||||
memcpy(stripdata, data + 1, 128 * 4);
|
stripe->delta_x = 0;
|
||||||
aesdev->strips = g_slist_prepend(aesdev->strips, stripdata);
|
stripe->delta_y = 0;
|
||||||
aesdev->strips_len++;
|
stripdata = stripe->data;
|
||||||
|
memcpy(stripdata, data + 1, FRAME_WIDTH * (FRAME_HEIGHT / 2));
|
||||||
|
aesdev->strips = g_slist_prepend(aesdev->strips, stripe);
|
||||||
|
aesdev->strips_len++;
|
||||||
aesdev->blanks_count = 0;
|
aesdev->blanks_count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sum < 0) {
|
if (sum < 0) {
|
||||||
fpi_ssm_mark_aborted(ssm, sum);
|
fpi_ssm_mark_failed(ssm, sum);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
fp_dbg("sum=%d", sum);
|
fp_dbg("sum=%d", sum);
|
||||||
@@ -609,24 +606,14 @@ static void capture_read_strip_cb(struct libusb_transfer *transfer)
|
|||||||
/* 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 (aesdev->blanks_count > 10 || g_slist_length(aesdev->strips) >= MAX_FRAMES) {
|
||||||
struct fp_img *img;
|
struct fp_img *img;
|
||||||
unsigned int height, rev_height;
|
|
||||||
|
|
||||||
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", aesdev->blanks_count, g_slist_length(aesdev->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);
|
aesdev->strips = g_slist_reverse(aesdev->strips);
|
||||||
height = aes_calc_delta(aesdev->strips, aesdev->strips_len,
|
fpi_do_movement_estimation(&assembling_ctx, aesdev->strips, aesdev->strips_len);
|
||||||
FRAME_WIDTH, FRAME_HEIGHT, FALSE);
|
img = fpi_assemble_frames(&assembling_ctx, aesdev->strips, aesdev->strips_len);
|
||||||
rev_height = aes_calc_delta(aesdev->strips, aesdev->strips_len,
|
img->flags |= FP_IMG_PARTIAL;
|
||||||
FRAME_WIDTH, FRAME_HEIGHT, TRUE);
|
|
||||||
fp_dbg("heights: %d rev: %d", height, rev_height);
|
|
||||||
if (rev_height < height) {
|
|
||||||
fp_dbg("Reversed direction");
|
|
||||||
height = aes_calc_delta(aesdev->strips, aesdev->strips_len,
|
|
||||||
FRAME_WIDTH, FRAME_HEIGHT, FALSE);
|
|
||||||
}
|
|
||||||
img = aes_assemble(aesdev->strips, aesdev->strips_len,
|
|
||||||
FRAME_WIDTH, FRAME_HEIGHT, FRAME_WIDTH + FRAME_WIDTH / 2);
|
|
||||||
g_slist_free_full(aesdev->strips, g_free);
|
g_slist_free_full(aesdev->strips, g_free);
|
||||||
aesdev->strips = NULL;
|
aesdev->strips = NULL;
|
||||||
aesdev->strips_len = 0;
|
aesdev->strips_len = 0;
|
||||||
@@ -647,13 +634,13 @@ out:
|
|||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void capture_run_state(struct fpi_ssm *ssm)
|
static void capture_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = user_data;
|
||||||
struct aes1610_dev *aesdev = dev->priv;
|
struct aes1610_dev *aesdev = FP_INSTANCE_DATA(_dev);
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
switch (ssm->cur_state) {
|
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),
|
||||||
@@ -661,7 +648,7 @@ static void capture_run_state(struct fpi_ssm *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");
|
||||||
@@ -672,38 +659,33 @@ static void capture_run_state(struct fpi_ssm *ssm)
|
|||||||
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);
|
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||||
unsigned char *data;
|
unsigned char *data;
|
||||||
|
|
||||||
if (!transfer) {
|
data = g_malloc(STRIP_CAPTURE_LEN);
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, data, STRIP_CAPTURE_LEN,
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
data = g_malloc(665);
|
|
||||||
libusb_fill_bulk_transfer(transfer, dev->udev, EP_IN, data, 665,
|
|
||||||
capture_read_strip_cb, ssm, BULK_TIMEOUT);
|
capture_read_strip_cb, ssm, BULK_TIMEOUT);
|
||||||
|
|
||||||
r = libusb_submit_transfer(transfer);
|
r = libusb_submit_transfer(transfer);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
g_free(data);
|
g_free(data);
|
||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
fpi_ssm_mark_aborted(ssm, r);
|
fpi_ssm_mark_failed(ssm, r);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static void capture_sm_complete(struct fpi_ssm *ssm)
|
static void capture_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = user_data;
|
||||||
struct aes1610_dev *aesdev = dev->priv;
|
struct aes1610_dev *aesdev = FP_INSTANCE_DATA(_dev);
|
||||||
|
|
||||||
fp_dbg("");
|
G_DEBUG_HERE();
|
||||||
if (aesdev->deactivating)
|
if (aesdev->deactivating)
|
||||||
complete_deactivation(dev);
|
complete_deactivation(dev);
|
||||||
else if (ssm->error)
|
else if (fpi_ssm_get_error(ssm))
|
||||||
fpi_imgdev_session_error(dev, ssm->error);
|
fpi_imgdev_session_error(dev, fpi_ssm_get_error(ssm));
|
||||||
else
|
else
|
||||||
start_finger_detection(dev);
|
start_finger_detection(dev);
|
||||||
fpi_ssm_free(ssm);
|
fpi_ssm_free(ssm);
|
||||||
@@ -711,17 +693,16 @@ static void capture_sm_complete(struct fpi_ssm *ssm)
|
|||||||
|
|
||||||
static void start_capture(struct fp_img_dev *dev)
|
static void start_capture(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct aes1610_dev *aesdev = dev->priv;
|
struct aes1610_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
struct fpi_ssm *ssm;
|
fpi_ssm *ssm;
|
||||||
|
|
||||||
if (aesdev->deactivating) {
|
if (aesdev->deactivating) {
|
||||||
complete_deactivation(dev);
|
complete_deactivation(dev);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssm = fpi_ssm_new(dev->dev, capture_run_state, CAPTURE_NUM_STATES);
|
ssm = fpi_ssm_new(FP_DEV(dev), capture_run_state, CAPTURE_NUM_STATES, dev);
|
||||||
fp_dbg("");
|
G_DEBUG_HERE();
|
||||||
ssm->priv = dev;
|
|
||||||
fpi_ssm_start(ssm, capture_sm_complete);
|
fpi_ssm_start(ssm, capture_sm_complete);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -731,23 +712,24 @@ static const struct aes_regwrite init[] = {
|
|||||||
{ 0x82, 0x00 }
|
{ 0x82, 0x00 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
static const struct aes_regwrite stop_reader[] = {
|
static const struct aes_regwrite stop_reader[] = {
|
||||||
{ 0xFF, 0x00 }
|
{ 0xFF, 0x00 }
|
||||||
};
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
enum activate_states {
|
enum activate_states {
|
||||||
WRITE_INIT,
|
WRITE_INIT,
|
||||||
ACTIVATE_NUM_STATES,
|
ACTIVATE_NUM_STATES,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void activate_run_state(struct fpi_ssm *ssm)
|
static void activate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = user_data;
|
||||||
|
|
||||||
/* 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 (ssm->cur_state) {
|
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);
|
||||||
@@ -756,23 +738,22 @@ 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(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = user_data;
|
||||||
fp_dbg("status %d", ssm->error);
|
fp_dbg("status %d", fpi_ssm_get_error(ssm));
|
||||||
fpi_imgdev_activate_complete(dev, ssm->error);
|
fpi_imgdev_activate_complete(dev, fpi_ssm_get_error(ssm));
|
||||||
|
|
||||||
if (!ssm->error)
|
if (!fpi_ssm_get_error(ssm))
|
||||||
start_finger_detection(dev);
|
start_finger_detection(dev);
|
||||||
fpi_ssm_free(ssm);
|
fpi_ssm_free(ssm);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
static int dev_activate(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct aes1610_dev *aesdev = dev->priv;
|
struct aes1610_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
struct fpi_ssm *ssm = fpi_ssm_new(dev->dev, activate_run_state,
|
fpi_ssm *ssm = fpi_ssm_new(FP_DEV(dev), activate_run_state,
|
||||||
ACTIVATE_NUM_STATES);
|
ACTIVATE_NUM_STATES, dev);
|
||||||
ssm->priv = dev;
|
|
||||||
aesdev->read_regs_retry_count = 0;
|
aesdev->read_regs_retry_count = 0;
|
||||||
fpi_ssm_start(ssm, activate_sm_complete);
|
fpi_ssm_start(ssm, activate_sm_complete);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -780,7 +761,7 @@ static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
|||||||
|
|
||||||
static void dev_deactivate(struct fp_img_dev *dev)
|
static void dev_deactivate(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct aes1610_dev *aesdev = dev->priv;
|
struct aes1610_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(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;
|
aesdev->deactivating = TRUE;
|
||||||
@@ -788,8 +769,8 @@ static void dev_deactivate(struct fp_img_dev *dev)
|
|||||||
|
|
||||||
static void complete_deactivation(struct fp_img_dev *dev)
|
static void complete_deactivation(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct aes1610_dev *aesdev = dev->priv;
|
struct aes1610_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
fp_dbg("");
|
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? */
|
||||||
@@ -806,22 +787,26 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
|||||||
{
|
{
|
||||||
/* FIXME check endpoints */
|
/* FIXME check endpoints */
|
||||||
int r;
|
int r;
|
||||||
|
struct aes1610_dev *aesdev;
|
||||||
|
|
||||||
r = libusb_claim_interface(dev->udev, 0);
|
r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
fp_err("could not claim interface 0");
|
fp_err("could not claim interface 0: %s", libusb_error_name(r));
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev->priv = g_malloc0(sizeof(struct aes1610_dev));
|
aesdev = g_malloc0(sizeof(struct aes1610_dev));
|
||||||
|
fp_dev_set_instance_data(FP_DEV(dev), aesdev);
|
||||||
fpi_imgdev_open_complete(dev, 0);
|
fpi_imgdev_open_complete(dev, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dev_deinit(struct fp_img_dev *dev)
|
static void dev_deinit(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
g_free(dev->priv);
|
struct aes1610_dev *aesdev;
|
||||||
libusb_release_interface(dev->udev, 0);
|
aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
g_free(aesdev);
|
||||||
|
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||||
fpi_imgdev_close_complete(dev);
|
fpi_imgdev_close_complete(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -840,9 +825,9 @@ struct fp_img_driver aes1610_driver = {
|
|||||||
},
|
},
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.img_height = -1,
|
.img_height = -1,
|
||||||
.img_width = FRAME_WIDTH + FRAME_WIDTH / 2,
|
.img_width = IMAGE_WIDTH,
|
||||||
|
|
||||||
.bz3_threshold = 50,
|
.bz3_threshold = 20,
|
||||||
|
|
||||||
.open = dev_init,
|
.open = dev_init,
|
||||||
.close = dev_deinit,
|
.close = dev_deinit,
|
||||||
|
|||||||
@@ -19,21 +19,20 @@
|
|||||||
|
|
||||||
#define FP_COMPONENT "aes1660"
|
#define FP_COMPONENT "aes1660"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include "drivers_api.h"
|
||||||
|
#include "aeslib.h"
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <libusb.h>
|
|
||||||
|
|
||||||
#include <fp_internal.h>
|
|
||||||
|
|
||||||
#include "aesx660.h"
|
#include "aesx660.h"
|
||||||
#include "aes1660.h"
|
#include "aes1660.h"
|
||||||
#include "driver_ids.h"
|
|
||||||
|
|
||||||
#define FRAME_WIDTH 128
|
#define FRAME_WIDTH 128
|
||||||
#define SCALE_FACTOR 2
|
#define IMAGE_WIDTH (FRAME_WIDTH + (FRAME_WIDTH / 2))
|
||||||
|
|
||||||
|
static struct fpi_frame_asmbl_ctx assembling_ctx = {
|
||||||
|
.frame_width = FRAME_WIDTH,
|
||||||
|
.frame_height = AESX660_FRAME_HEIGHT,
|
||||||
|
.image_width = IMAGE_WIDTH,
|
||||||
|
.get_pixel = aes_get_pixel,
|
||||||
|
};
|
||||||
|
|
||||||
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||||
{
|
{
|
||||||
@@ -41,21 +40,23 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
|||||||
int r;
|
int r;
|
||||||
struct aesX660_dev *aesdev;
|
struct aesX660_dev *aesdev;
|
||||||
|
|
||||||
r = libusb_claim_interface(dev->udev, 0);
|
r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
fp_err("could not claim interface 0");
|
fp_err("could not claim interface 0: %s", libusb_error_name(r));
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev->priv = aesdev = g_malloc0(sizeof(struct aesX660_dev));
|
aesdev = g_malloc0(sizeof(struct aesX660_dev));
|
||||||
|
fp_dev_set_instance_data(FP_DEV(dev), aesdev);
|
||||||
aesdev->buffer = g_malloc0(AES1660_FRAME_SIZE + AESX660_HEADER_SIZE);
|
aesdev->buffer = g_malloc0(AES1660_FRAME_SIZE + AESX660_HEADER_SIZE);
|
||||||
aesdev->init_seqs[0] = aes1660_init_1;
|
aesdev->init_seqs[0] = aes1660_init_1;
|
||||||
aesdev->init_seqs_len[0] = array_n_elements(aes1660_init_1);
|
aesdev->init_seqs_len[0] = G_N_ELEMENTS(aes1660_init_1);
|
||||||
aesdev->init_seqs[1] = aes1660_init_2;
|
aesdev->init_seqs[1] = aes1660_init_2;
|
||||||
aesdev->init_seqs_len[1] = array_n_elements(aes1660_init_2);
|
aesdev->init_seqs_len[1] = G_N_ELEMENTS(aes1660_init_2);
|
||||||
aesdev->start_imaging_cmd = (unsigned char *)aes1660_start_imaging_cmd;
|
aesdev->start_imaging_cmd = (unsigned char *)aes1660_start_imaging_cmd;
|
||||||
aesdev->start_imaging_cmd_len = sizeof(aes1660_start_imaging_cmd);
|
aesdev->start_imaging_cmd_len = sizeof(aes1660_start_imaging_cmd);
|
||||||
aesdev->frame_width = FRAME_WIDTH;
|
aesdev->assembling_ctx = &assembling_ctx;
|
||||||
|
aesdev->extra_img_flags = FP_IMG_PARTIAL;
|
||||||
|
|
||||||
fpi_imgdev_open_complete(dev, 0);
|
fpi_imgdev_open_complete(dev, 0);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -63,10 +64,10 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
|||||||
|
|
||||||
static void dev_deinit(struct fp_img_dev *dev)
|
static void dev_deinit(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct aesX660_dev *aesdev = dev->priv;
|
struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
g_free(aesdev->buffer);
|
g_free(aesdev->buffer);
|
||||||
g_free(aesdev);
|
g_free(aesdev);
|
||||||
libusb_release_interface(dev->udev, 0);
|
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||||
fpi_imgdev_close_complete(dev);
|
fpi_imgdev_close_complete(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,7 +103,7 @@ struct fp_img_driver aes1660_driver = {
|
|||||||
.flags = 0,
|
.flags = 0,
|
||||||
.img_height = -1,
|
.img_height = -1,
|
||||||
.img_width = FRAME_WIDTH + FRAME_WIDTH / 2,
|
.img_width = FRAME_WIDTH + FRAME_WIDTH / 2,
|
||||||
.bz3_threshold = 70,
|
.bz3_threshold = 20,
|
||||||
|
|
||||||
.open = dev_init,
|
.open = dev_init,
|
||||||
.close = dev_deinit,
|
.close = dev_deinit,
|
||||||
|
|||||||
@@ -23,16 +23,9 @@
|
|||||||
|
|
||||||
#define FP_COMPONENT "aes2501"
|
#define FP_COMPONENT "aes2501"
|
||||||
|
|
||||||
#include <errno.h>
|
#include "drivers_api.h"
|
||||||
#include <string.h>
|
#include "aeslib.h"
|
||||||
|
|
||||||
#include <libusb.h>
|
|
||||||
|
|
||||||
#include <aeslib.h>
|
|
||||||
#include <fp_internal.h>
|
|
||||||
|
|
||||||
#include "aes2501.h"
|
#include "aes2501.h"
|
||||||
#include "driver_ids.h"
|
|
||||||
|
|
||||||
static void start_capture(struct fp_img_dev *dev);
|
static void start_capture(struct fp_img_dev *dev);
|
||||||
static void complete_deactivation(struct fp_img_dev *dev);
|
static void complete_deactivation(struct fp_img_dev *dev);
|
||||||
@@ -43,6 +36,11 @@ static void complete_deactivation(struct fp_img_dev *dev);
|
|||||||
|
|
||||||
#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,6 +56,7 @@ static void complete_deactivation(struct fp_img_dev *dev);
|
|||||||
#define FRAME_WIDTH 192
|
#define FRAME_WIDTH 192
|
||||||
#define FRAME_HEIGHT 16
|
#define FRAME_HEIGHT 16
|
||||||
#define FRAME_SIZE (FRAME_WIDTH * FRAME_HEIGHT)
|
#define FRAME_SIZE (FRAME_WIDTH * FRAME_HEIGHT)
|
||||||
|
#define IMAGE_WIDTH (FRAME_WIDTH + (FRAME_WIDTH / 2))
|
||||||
/* maximum number of frames to read during a scan */
|
/* maximum number of frames to read during a scan */
|
||||||
/* FIXME reduce substantially */
|
/* FIXME reduce substantially */
|
||||||
#define MAX_FRAMES 150
|
#define MAX_FRAMES 150
|
||||||
@@ -72,6 +71,13 @@ struct aes2501_dev {
|
|||||||
int no_finger_cnt;
|
int no_finger_cnt;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct fpi_frame_asmbl_ctx assembling_ctx = {
|
||||||
|
.frame_width = FRAME_WIDTH,
|
||||||
|
.frame_height = FRAME_HEIGHT,
|
||||||
|
.image_width = IMAGE_WIDTH,
|
||||||
|
.get_pixel = aes_get_pixel,
|
||||||
|
};
|
||||||
|
|
||||||
typedef void (*aes2501_read_regs_cb)(struct fp_img_dev *dev, int status,
|
typedef void (*aes2501_read_regs_cb)(struct fp_img_dev *dev, int status,
|
||||||
unsigned char *regs, void *user_data);
|
unsigned char *regs, void *user_data);
|
||||||
|
|
||||||
@@ -82,9 +88,12 @@ struct aes2501_read_regs {
|
|||||||
void *user_data;
|
void *user_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void read_regs_data_cb(struct libusb_transfer *transfer)
|
static void read_regs_data_cb(struct libusb_transfer *transfer,
|
||||||
|
struct fp_dev *dev,
|
||||||
|
fpi_ssm *ssm,
|
||||||
|
void *user_data)
|
||||||
{
|
{
|
||||||
struct aes2501_read_regs *rdata = transfer->user_data;
|
struct aes2501_read_regs *rdata = user_data;
|
||||||
unsigned char *retdata = NULL;
|
unsigned char *retdata = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@@ -99,14 +108,12 @@ static void read_regs_data_cb(struct libusb_transfer *transfer)
|
|||||||
|
|
||||||
rdata->callback(rdata->dev, r, retdata, rdata->user_data);
|
rdata->callback(rdata->dev, r, retdata, rdata->user_data);
|
||||||
g_free(rdata);
|
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)
|
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;
|
fpi_usb_transfer *transfer;
|
||||||
unsigned char *data;
|
unsigned char *data;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@@ -114,20 +121,18 @@ static void read_regs_rq_cb(struct fp_img_dev *dev, int result, void *user_data)
|
|||||||
if (result != 0)
|
if (result != 0)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
transfer = libusb_alloc_transfer(0);
|
data = g_malloc(READ_REGS_LEN);
|
||||||
if (!transfer) {
|
transfer = fpi_usb_fill_bulk_transfer(FP_DEV(dev),
|
||||||
result = -ENOMEM;
|
NULL,
|
||||||
goto err;
|
EP_IN,
|
||||||
}
|
data,
|
||||||
|
READ_REGS_LEN,
|
||||||
|
read_regs_data_cb,
|
||||||
|
rdata,
|
||||||
|
BULK_TIMEOUT);
|
||||||
|
|
||||||
data = g_malloc(126);
|
r = fpi_usb_submit_transfer(transfer);
|
||||||
libusb_fill_bulk_transfer(transfer, dev->udev, EP_IN, data, 126,
|
|
||||||
read_regs_data_cb, rdata, BULK_TIMEOUT);
|
|
||||||
|
|
||||||
r = libusb_submit_transfer(transfer);
|
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
g_free(data);
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
result = -EIO;
|
result = -EIO;
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
@@ -146,7 +151,7 @@ static void read_regs(struct fp_img_dev *dev, aes2501_read_regs_cb callback,
|
|||||||
struct aes_regwrite *regwrite = g_malloc(sizeof(*regwrite));
|
struct aes_regwrite *regwrite = g_malloc(sizeof(*regwrite));
|
||||||
struct aes2501_read_regs *rdata = g_malloc(sizeof(*rdata));
|
struct aes2501_read_regs *rdata = g_malloc(sizeof(*rdata));
|
||||||
|
|
||||||
fp_dbg("");
|
G_DEBUG_HERE();
|
||||||
regwrite->reg = AES2501_REG_CTRL2;
|
regwrite->reg = AES2501_REG_CTRL2;
|
||||||
regwrite->value = AES2501_CTRL2_READ_REGS;
|
regwrite->value = AES2501_CTRL2_READ_REGS;
|
||||||
rdata->dev = dev;
|
rdata->dev = dev;
|
||||||
@@ -179,52 +184,48 @@ static int regval_from_dump(unsigned char *data, uint8_t target)
|
|||||||
static void generic_write_regv_cb(struct fp_img_dev *dev, int result,
|
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;
|
fpi_ssm *ssm = user_data;
|
||||||
if (result == 0)
|
if (result == 0)
|
||||||
fpi_ssm_next_state(ssm);
|
fpi_ssm_next_state(ssm);
|
||||||
else
|
else
|
||||||
fpi_ssm_mark_aborted(ssm, result);
|
fpi_ssm_mark_failed(ssm, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check that read succeeded but ignore all data */
|
/* check that read succeeded but ignore all data */
|
||||||
static void generic_ignore_data_cb(struct libusb_transfer *transfer)
|
static void generic_ignore_data_cb(struct libusb_transfer *transfer,
|
||||||
|
struct fp_dev *dev,
|
||||||
|
fpi_ssm *ssm,
|
||||||
|
void *user_data)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
|
||||||
|
|
||||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
|
if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
else if (transfer->length != transfer->actual_length)
|
else if (transfer->length != transfer->actual_length)
|
||||||
fpi_ssm_mark_aborted(ssm, -EPROTO);
|
fpi_ssm_mark_failed(ssm, -EPROTO);
|
||||||
else
|
else
|
||||||
fpi_ssm_next_state(ssm);
|
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(fpi_ssm *ssm, struct fp_dev *dev, size_t bytes)
|
||||||
{
|
{
|
||||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
fpi_usb_transfer *transfer;
|
||||||
unsigned char *data;
|
unsigned char *data;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (!transfer) {
|
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
data = g_malloc(bytes);
|
data = g_malloc(bytes);
|
||||||
libusb_fill_bulk_transfer(transfer, ssm->dev->udev, EP_IN, data, bytes,
|
transfer = fpi_usb_fill_bulk_transfer(dev,
|
||||||
generic_ignore_data_cb, ssm, BULK_TIMEOUT);
|
ssm,
|
||||||
|
EP_IN,
|
||||||
|
data,
|
||||||
|
bytes,
|
||||||
|
generic_ignore_data_cb,
|
||||||
|
NULL,
|
||||||
|
BULK_TIMEOUT);
|
||||||
|
|
||||||
r = libusb_submit_transfer(transfer);
|
r = fpi_usb_submit_transfer(transfer);
|
||||||
if (r < 0) {
|
if (r < 0)
|
||||||
g_free(data);
|
fpi_ssm_mark_failed(ssm, r);
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
fpi_ssm_mark_aborted(ssm, r);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/****** IMAGE PROCESSING ******/
|
/****** IMAGE PROCESSING ******/
|
||||||
@@ -280,19 +281,22 @@ static const struct aes_regwrite finger_det_reqs[] = {
|
|||||||
|
|
||||||
static void start_finger_detection(struct fp_img_dev *dev);
|
static void start_finger_detection(struct fp_img_dev *dev);
|
||||||
|
|
||||||
static void finger_det_data_cb(struct libusb_transfer *transfer)
|
static void finger_det_data_cb(struct libusb_transfer *transfer,
|
||||||
|
struct fp_dev *_dev,
|
||||||
|
fpi_ssm *ssm,
|
||||||
|
void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = transfer->user_data;
|
struct fp_img_dev *dev = FP_IMG_DEV(_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 (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||||
fpi_imgdev_session_error(dev, -EIO);
|
fpi_imgdev_session_error(dev, -EIO);
|
||||||
goto out;
|
return;
|
||||||
} else if (transfer->length != transfer->actual_length) {
|
} else if (transfer->length != transfer->actual_length) {
|
||||||
fpi_imgdev_session_error(dev, -EPROTO);
|
fpi_imgdev_session_error(dev, -EPROTO);
|
||||||
goto out;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* examine histogram to determine finger presence */
|
/* examine histogram to determine finger presence */
|
||||||
@@ -306,16 +310,12 @@ static void finger_det_data_cb(struct libusb_transfer *transfer)
|
|||||||
/* 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(struct fp_img_dev *dev, int result,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
struct libusb_transfer *transfer;
|
fpi_usb_transfer *transfer;
|
||||||
unsigned char *data;
|
unsigned char *data;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@@ -324,28 +324,25 @@ static void finger_det_reqs_cb(struct fp_img_dev *dev, int result,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
transfer = libusb_alloc_transfer(0);
|
data = g_malloc(FINGER_DETECTION_LEN);
|
||||||
if (!transfer) {
|
transfer = fpi_usb_fill_bulk_transfer(FP_DEV(dev),
|
||||||
fpi_imgdev_session_error(dev, -ENOMEM);
|
NULL,
|
||||||
return;
|
EP_IN,
|
||||||
}
|
data,
|
||||||
|
FINGER_DETECTION_LEN,
|
||||||
|
finger_det_data_cb,
|
||||||
|
NULL,
|
||||||
|
BULK_TIMEOUT);
|
||||||
|
|
||||||
data = g_malloc(20);
|
r = fpi_usb_submit_transfer(transfer);
|
||||||
libusb_fill_bulk_transfer(transfer, dev->udev, EP_IN, data, 20,
|
if (r < 0)
|
||||||
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);
|
fpi_imgdev_session_error(dev, r);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void start_finger_detection(struct fp_img_dev *dev)
|
static void start_finger_detection(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct aes2501_dev *aesdev = dev->priv;
|
struct aes2501_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
fp_dbg("");
|
G_DEBUG_HERE();
|
||||||
|
|
||||||
if (aesdev->deactivating) {
|
if (aesdev->deactivating) {
|
||||||
complete_deactivation(dev);
|
complete_deactivation(dev);
|
||||||
@@ -418,7 +415,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 {
|
||||||
@@ -431,35 +428,37 @@ 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(struct libusb_transfer *transfer,
|
||||||
|
struct fp_dev *_dev,
|
||||||
|
fpi_ssm *ssm,
|
||||||
|
void *user_data)
|
||||||
{
|
{
|
||||||
unsigned char *stripdata;
|
unsigned char *stripdata;
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
struct fp_img_dev *dev = FP_IMG_DEV(_dev);
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct aes2501_dev *aesdev = FP_INSTANCE_DATA(_dev);
|
||||||
struct aes2501_dev *aesdev = dev->priv;
|
|
||||||
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 (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
goto out;
|
return;
|
||||||
} else if (transfer->length != transfer->actual_length) {
|
} else if (transfer->length != transfer->actual_length) {
|
||||||
fpi_ssm_mark_aborted(ssm, -EPROTO);
|
fpi_ssm_mark_failed(ssm, -EPROTO);
|
||||||
goto out;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
fpi_ssm_mark_failed(ssm, threshold);
|
||||||
goto out;
|
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);
|
fpi_ssm_mark_failed(ssm, sum);
|
||||||
goto out;
|
return;
|
||||||
}
|
}
|
||||||
fp_dbg("sum=%d", sum);
|
fp_dbg("sum=%d", sum);
|
||||||
|
|
||||||
@@ -481,21 +480,13 @@ static void capture_read_strip_cb(struct libusb_transfer *transfer)
|
|||||||
aesdev->no_finger_cnt++;
|
aesdev->no_finger_cnt++;
|
||||||
if (aesdev->no_finger_cnt == 3) {
|
if (aesdev->no_finger_cnt == 3) {
|
||||||
struct fp_img *img;
|
struct fp_img *img;
|
||||||
unsigned int height, rev_height;
|
|
||||||
|
|
||||||
aesdev->strips = g_slist_reverse(aesdev->strips);
|
aesdev->strips = g_slist_reverse(aesdev->strips);
|
||||||
height = aes_calc_delta(aesdev->strips, aesdev->strips_len,
|
fpi_do_movement_estimation(&assembling_ctx,
|
||||||
FRAME_WIDTH, FRAME_HEIGHT, FALSE);
|
aesdev->strips, aesdev->strips_len);
|
||||||
rev_height = aes_calc_delta(aesdev->strips, aesdev->strips_len,
|
img = fpi_assemble_frames(&assembling_ctx,
|
||||||
FRAME_WIDTH, FRAME_HEIGHT, TRUE);
|
aesdev->strips, aesdev->strips_len);
|
||||||
fp_dbg("heights: %d rev: %d", height, rev_height);
|
img->flags |= FP_IMG_PARTIAL;
|
||||||
if (rev_height < height) {
|
|
||||||
fp_dbg("Reversed direction");
|
|
||||||
height = aes_calc_delta(aesdev->strips, aesdev->strips_len,
|
|
||||||
FRAME_WIDTH, FRAME_HEIGHT, FALSE);
|
|
||||||
}
|
|
||||||
img = aes_assemble(aesdev->strips, aesdev->strips_len,
|
|
||||||
FRAME_WIDTH, FRAME_HEIGHT, FRAME_WIDTH + FRAME_WIDTH / 2);
|
|
||||||
g_slist_free_full(aesdev->strips, g_free);
|
g_slist_free_full(aesdev->strips, g_free);
|
||||||
aesdev->strips = NULL;
|
aesdev->strips = NULL;
|
||||||
aesdev->strips_len = 0;
|
aesdev->strips_len = 0;
|
||||||
@@ -509,7 +500,7 @@ static void capture_read_strip_cb(struct libusb_transfer *transfer)
|
|||||||
} 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 aes_stripe *stripe = g_malloc(FRAME_WIDTH * FRAME_HEIGHT / 2 + sizeof(struct aes_stripe));
|
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;
|
||||||
@@ -520,32 +511,28 @@ static void capture_read_strip_cb(struct libusb_transfer *transfer)
|
|||||||
|
|
||||||
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(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = user_data;
|
||||||
struct aes2501_dev *aesdev = dev->priv;
|
struct aes2501_dev *aesdev = FP_INSTANCE_DATA(_dev);
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
switch (ssm->cur_state) {
|
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, _dev, 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, _dev, READ_REGS_RESP_LEN);
|
||||||
break;
|
break;
|
||||||
case CAPTURE_REQUEST_STRIP:
|
case CAPTURE_REQUEST_STRIP:
|
||||||
if (aesdev->deactivating)
|
if (aesdev->deactivating)
|
||||||
@@ -555,38 +542,36 @@ static void capture_run_state(struct fpi_ssm *ssm)
|
|||||||
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);
|
fpi_usb_transfer *transfer;
|
||||||
unsigned char *data;
|
unsigned char *data;
|
||||||
|
|
||||||
if (!transfer) {
|
data = g_malloc(STRIP_CAPTURE_LEN);
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
transfer = fpi_usb_fill_bulk_transfer(FP_DEV(dev),
|
||||||
break;
|
ssm,
|
||||||
}
|
EP_IN,
|
||||||
|
data,
|
||||||
|
STRIP_CAPTURE_LEN,
|
||||||
|
capture_read_strip_cb,
|
||||||
|
NULL,
|
||||||
|
BULK_TIMEOUT);
|
||||||
|
|
||||||
data = g_malloc(1705);
|
r = fpi_usb_submit_transfer(transfer);
|
||||||
libusb_fill_bulk_transfer(transfer, dev->udev, EP_IN, data, 1705,
|
if (r < 0)
|
||||||
capture_read_strip_cb, ssm, BULK_TIMEOUT);
|
fpi_ssm_mark_failed(ssm, r);
|
||||||
|
|
||||||
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(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = user_data;
|
||||||
struct aes2501_dev *aesdev = dev->priv;
|
struct aes2501_dev *aesdev = FP_INSTANCE_DATA(_dev);
|
||||||
|
|
||||||
fp_dbg("");
|
G_DEBUG_HERE();
|
||||||
if (aesdev->deactivating)
|
if (aesdev->deactivating)
|
||||||
complete_deactivation(dev);
|
complete_deactivation(dev);
|
||||||
else if (ssm->error)
|
else if (fpi_ssm_get_error(ssm))
|
||||||
fpi_imgdev_session_error(dev, ssm->error);
|
fpi_imgdev_session_error(dev, fpi_ssm_get_error(ssm));
|
||||||
else
|
else
|
||||||
start_finger_detection(dev);
|
start_finger_detection(dev);
|
||||||
fpi_ssm_free(ssm);
|
fpi_ssm_free(ssm);
|
||||||
@@ -594,8 +579,8 @@ static void capture_sm_complete(struct fpi_ssm *ssm)
|
|||||||
|
|
||||||
static void start_capture(struct fp_img_dev *dev)
|
static void start_capture(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct aes2501_dev *aesdev = dev->priv;
|
struct aes2501_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
struct fpi_ssm *ssm;
|
fpi_ssm *ssm;
|
||||||
|
|
||||||
if (aesdev->deactivating) {
|
if (aesdev->deactivating) {
|
||||||
complete_deactivation(dev);
|
complete_deactivation(dev);
|
||||||
@@ -605,9 +590,8 @@ static void start_capture(struct fp_img_dev *dev)
|
|||||||
aesdev->no_finger_cnt = 0;
|
aesdev->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(dev->dev, capture_run_state, CAPTURE_NUM_STATES);
|
ssm = fpi_ssm_new(FP_DEV(dev), capture_run_state, CAPTURE_NUM_STATES, dev);
|
||||||
fp_dbg("");
|
G_DEBUG_HERE();
|
||||||
ssm->priv = dev;
|
|
||||||
fpi_ssm_start(ssm, capture_sm_complete);
|
fpi_ssm_start(ssm, capture_sm_complete);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -719,11 +703,11 @@ enum activate_states {
|
|||||||
void activate_read_regs_cb(struct fp_img_dev *dev, int status,
|
void activate_read_regs_cb(struct fp_img_dev *dev, int status,
|
||||||
unsigned char *regs, void *user_data)
|
unsigned char *regs, void *user_data)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = user_data;
|
fpi_ssm *ssm = user_data;
|
||||||
struct aes2501_dev *aesdev = dev->priv;
|
struct aes2501_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
|
||||||
if (status != 0) {
|
if (status != 0) {
|
||||||
fpi_ssm_mark_aborted(ssm, status);
|
fpi_ssm_mark_failed(ssm, status);
|
||||||
} else {
|
} 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 || ++aesdev->read_regs_retry_count == 13)
|
||||||
@@ -736,16 +720,16 @@ void activate_read_regs_cb(struct fp_img_dev *dev, int status,
|
|||||||
static void activate_init3_cb(struct fp_img_dev *dev, int result,
|
static void activate_init3_cb(struct fp_img_dev *dev, int result,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = user_data;
|
fpi_ssm *ssm = user_data;
|
||||||
if (result == 0)
|
if (result == 0)
|
||||||
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, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void activate_run_state(struct fpi_ssm *ssm)
|
static void activate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = user_data;
|
||||||
|
|
||||||
/* 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
|
||||||
@@ -766,14 +750,14 @@ static void activate_run_state(struct fpi_ssm *ssm)
|
|||||||
aes_write_regv(init_4);
|
aes_write_regv(init_4);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
switch (ssm->cur_state) {
|
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),
|
||||||
@@ -783,7 +767,7 @@ static void activate_run_state(struct fpi_ssm *ssm)
|
|||||||
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_4, G_N_ELEMENTS(init_4),
|
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:
|
||||||
@@ -797,23 +781,22 @@ static void activate_run_state(struct fpi_ssm *ssm)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void activate_sm_complete(struct fpi_ssm *ssm)
|
static void activate_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = user_data;
|
||||||
fp_dbg("status %d", ssm->error);
|
fp_dbg("status %d", fpi_ssm_get_error(ssm));
|
||||||
fpi_imgdev_activate_complete(dev, ssm->error);
|
fpi_imgdev_activate_complete(dev, fpi_ssm_get_error(ssm));
|
||||||
|
|
||||||
if (!ssm->error)
|
if (!fpi_ssm_get_error(ssm))
|
||||||
start_finger_detection(dev);
|
start_finger_detection(dev);
|
||||||
fpi_ssm_free(ssm);
|
fpi_ssm_free(ssm);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
static int dev_activate(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct aes2501_dev *aesdev = dev->priv;
|
struct aes2501_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
struct fpi_ssm *ssm = fpi_ssm_new(dev->dev, activate_run_state,
|
fpi_ssm *ssm = fpi_ssm_new(FP_DEV(dev), activate_run_state,
|
||||||
ACTIVATE_NUM_STATES);
|
ACTIVATE_NUM_STATES, dev);
|
||||||
ssm->priv = dev;
|
|
||||||
aesdev->read_regs_retry_count = 0;
|
aesdev->read_regs_retry_count = 0;
|
||||||
fpi_ssm_start(ssm, activate_sm_complete);
|
fpi_ssm_start(ssm, activate_sm_complete);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -821,7 +804,7 @@ static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
|||||||
|
|
||||||
static void dev_deactivate(struct fp_img_dev *dev)
|
static void dev_deactivate(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct aes2501_dev *aesdev = dev->priv;
|
struct aes2501_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(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;
|
aesdev->deactivating = TRUE;
|
||||||
@@ -829,8 +812,8 @@ static void dev_deactivate(struct fp_img_dev *dev)
|
|||||||
|
|
||||||
static void complete_deactivation(struct fp_img_dev *dev)
|
static void complete_deactivation(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct aes2501_dev *aesdev = dev->priv;
|
struct aes2501_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
fp_dbg("");
|
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? */
|
||||||
@@ -846,22 +829,25 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
|||||||
{
|
{
|
||||||
/* FIXME check endpoints */
|
/* FIXME check endpoints */
|
||||||
int r;
|
int r;
|
||||||
|
struct aes2501_dev *aesdev;
|
||||||
|
|
||||||
r = libusb_claim_interface(dev->udev, 0);
|
r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
fp_err("could not claim interface 0");
|
fp_err("could not claim interface 0: %s", libusb_error_name(r));
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev->priv = g_malloc0(sizeof(struct aes2501_dev));
|
aesdev = g_malloc0(sizeof(struct aes2501_dev));
|
||||||
|
fp_dev_set_instance_data(FP_DEV(dev), aesdev);
|
||||||
fpi_imgdev_open_complete(dev, 0);
|
fpi_imgdev_open_complete(dev, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dev_deinit(struct fp_img_dev *dev)
|
static void dev_deinit(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
g_free(dev->priv);
|
struct aes2501_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
libusb_release_interface(dev->udev, 0);
|
g_free(aesdev);
|
||||||
|
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||||
fpi_imgdev_close_complete(dev);
|
fpi_imgdev_close_complete(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -881,7 +867,7 @@ struct fp_img_driver aes2501_driver = {
|
|||||||
},
|
},
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
.img_height = -1,
|
.img_height = -1,
|
||||||
.img_width = FRAME_WIDTH + FRAME_WIDTH / 2,
|
.img_width = IMAGE_WIDTH,
|
||||||
|
|
||||||
.open = dev_init,
|
.open = dev_init,
|
||||||
.close = dev_deinit,
|
.close = dev_deinit,
|
||||||
|
|||||||
@@ -109,7 +109,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 {
|
||||||
|
|||||||
@@ -23,16 +23,9 @@
|
|||||||
|
|
||||||
#define FP_COMPONENT "aes2550"
|
#define FP_COMPONENT "aes2550"
|
||||||
|
|
||||||
#include <errno.h>
|
#include "drivers_api.h"
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <libusb.h>
|
|
||||||
|
|
||||||
#include <aeslib.h>
|
|
||||||
#include <fp_internal.h>
|
|
||||||
|
|
||||||
#include "aes2550.h"
|
#include "aes2550.h"
|
||||||
#include "driver_ids.h"
|
#include "aeslib.h"
|
||||||
|
|
||||||
static void start_capture(struct fp_img_dev *dev);
|
static void start_capture(struct fp_img_dev *dev);
|
||||||
static void complete_deactivation(struct fp_img_dev *dev);
|
static void complete_deactivation(struct fp_img_dev *dev);
|
||||||
@@ -56,6 +49,7 @@ static void complete_deactivation(struct fp_img_dev *dev);
|
|||||||
#define FRAME_WIDTH 192
|
#define FRAME_WIDTH 192
|
||||||
#define FRAME_HEIGHT 8
|
#define FRAME_HEIGHT 8
|
||||||
#define FRAME_SIZE (FRAME_WIDTH * FRAME_HEIGHT)
|
#define FRAME_SIZE (FRAME_WIDTH * FRAME_HEIGHT)
|
||||||
|
#define IMAGE_WIDTH (FRAME_WIDTH + (FRAME_WIDTH / 2))
|
||||||
|
|
||||||
struct aes2550_dev {
|
struct aes2550_dev {
|
||||||
GSList *strips;
|
GSList *strips;
|
||||||
@@ -64,6 +58,13 @@ struct aes2550_dev {
|
|||||||
int heartbeat_cnt;
|
int heartbeat_cnt;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct fpi_frame_asmbl_ctx assembling_ctx = {
|
||||||
|
.frame_width = FRAME_WIDTH,
|
||||||
|
.frame_height = FRAME_HEIGHT,
|
||||||
|
.image_width = IMAGE_WIDTH,
|
||||||
|
.get_pixel = aes_get_pixel,
|
||||||
|
};
|
||||||
|
|
||||||
/****** FINGER PRESENCE DETECTION ******/
|
/****** FINGER PRESENCE DETECTION ******/
|
||||||
|
|
||||||
static unsigned char finger_det_reqs[] = {
|
static unsigned char finger_det_reqs[] = {
|
||||||
@@ -124,15 +125,10 @@ static void finger_det_reqs_cb(struct libusb_transfer *t)
|
|||||||
goto exit_free_transfer;
|
goto exit_free_transfer;
|
||||||
}
|
}
|
||||||
|
|
||||||
transfer = libusb_alloc_transfer(0);
|
transfer = fpi_usb_alloc();
|
||||||
if (!transfer) {
|
|
||||||
fpi_imgdev_session_error(dev, -ENOMEM);
|
|
||||||
goto exit_free_transfer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 2 bytes of result */
|
/* 2 bytes of result */
|
||||||
data = g_malloc(AES2550_EP_IN_BUF_SIZE);
|
data = g_malloc(AES2550_EP_IN_BUF_SIZE);
|
||||||
libusb_fill_bulk_transfer(transfer, dev->udev, EP_IN, data, AES2550_EP_IN_BUF_SIZE,
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, data, AES2550_EP_IN_BUF_SIZE,
|
||||||
finger_det_data_cb, dev, BULK_TIMEOUT);
|
finger_det_data_cb, dev, BULK_TIMEOUT);
|
||||||
|
|
||||||
r = libusb_submit_transfer(transfer);
|
r = libusb_submit_transfer(transfer);
|
||||||
@@ -148,21 +144,17 @@ exit_free_transfer:
|
|||||||
static void start_finger_detection(struct fp_img_dev *dev)
|
static void start_finger_detection(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
struct aes2550_dev *aesdev = dev->priv;
|
struct aes2550_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
struct libusb_transfer *transfer;
|
struct libusb_transfer *transfer;
|
||||||
fp_dbg("");
|
G_DEBUG_HERE();
|
||||||
|
|
||||||
if (aesdev->deactivating) {
|
if (aesdev->deactivating) {
|
||||||
complete_deactivation(dev);
|
complete_deactivation(dev);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
transfer = libusb_alloc_transfer(0);
|
transfer = fpi_usb_alloc();
|
||||||
if (!transfer) {
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_OUT, finger_det_reqs,
|
||||||
fpi_imgdev_session_error(dev, -ENOMEM);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
libusb_fill_bulk_transfer(transfer, dev->udev, EP_OUT, finger_det_reqs,
|
|
||||||
sizeof(finger_det_reqs), finger_det_reqs_cb, dev, BULK_TIMEOUT);
|
sizeof(finger_det_reqs), finger_det_reqs_cb, dev, BULK_TIMEOUT);
|
||||||
r = libusb_submit_transfer(transfer);
|
r = libusb_submit_transfer(transfer);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
@@ -199,12 +191,11 @@ 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 int process_strip_data(fpi_ssm *ssm, struct fp_img_dev *dev, unsigned char *data)
|
||||||
{
|
{
|
||||||
unsigned char *stripdata;
|
unsigned char *stripdata;
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct aes2550_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
struct aes2550_dev *aesdev = dev->priv;
|
struct fpi_frame *stripe;
|
||||||
struct aes_stripe *stripe;
|
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
if (data[0] != AES2550_EDATA_MAGIC) {
|
if (data[0] != AES2550_EDATA_MAGIC) {
|
||||||
@@ -215,7 +206,7 @@ static int process_strip_data(struct fpi_ssm *ssm, unsigned char *data)
|
|||||||
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_malloc(FRAME_WIDTH * FRAME_HEIGHT / 2 + sizeof(struct aes_stripe)); /* 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;
|
||||||
@@ -230,22 +221,22 @@ static int process_strip_data(struct fpi_ssm *ssm, unsigned char *data)
|
|||||||
|
|
||||||
static void capture_reqs_cb(struct libusb_transfer *transfer)
|
static void capture_reqs_cb(struct libusb_transfer *transfer)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
|
|
||||||
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
|
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
|
||||||
(transfer->length == transfer->actual_length)) {
|
(transfer->length == transfer->actual_length)) {
|
||||||
fpi_ssm_next_state(ssm);
|
fpi_ssm_next_state(ssm);
|
||||||
} else {
|
} else {
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
}
|
}
|
||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void capture_set_idle_reqs_cb(struct libusb_transfer *transfer)
|
static void capture_set_idle_reqs_cb(struct libusb_transfer *transfer)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
||||||
struct aes2550_dev *aesdev = dev->priv;
|
struct aes2550_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
|
||||||
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
|
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
|
||||||
(transfer->length == transfer->actual_length) &&
|
(transfer->length == transfer->actual_length) &&
|
||||||
@@ -253,8 +244,9 @@ static void capture_set_idle_reqs_cb(struct libusb_transfer *transfer)
|
|||||||
struct fp_img *img;
|
struct fp_img *img;
|
||||||
|
|
||||||
aesdev->strips = g_slist_reverse(aesdev->strips);
|
aesdev->strips = g_slist_reverse(aesdev->strips);
|
||||||
img = aes_assemble(aesdev->strips, aesdev->strips_len,
|
img = fpi_assemble_frames(&assembling_ctx,
|
||||||
FRAME_WIDTH, FRAME_HEIGHT, FRAME_WIDTH + FRAME_WIDTH / 2);
|
aesdev->strips, aesdev->strips_len);
|
||||||
|
img->flags |= FP_IMG_PARTIAL;
|
||||||
g_slist_free_full(aesdev->strips, g_free);
|
g_slist_free_full(aesdev->strips, g_free);
|
||||||
aesdev->strips = NULL;
|
aesdev->strips = NULL;
|
||||||
aesdev->strips_len = 0;
|
aesdev->strips_len = 0;
|
||||||
@@ -263,22 +255,22 @@ static void capture_set_idle_reqs_cb(struct libusb_transfer *transfer)
|
|||||||
/* 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_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
}
|
}
|
||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void capture_read_data_cb(struct libusb_transfer *transfer)
|
static void capture_read_data_cb(struct libusb_transfer *transfer)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
||||||
struct aes2550_dev *aesdev = dev->priv;
|
struct aes2550_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
unsigned char *data = transfer->buffer;
|
unsigned char *data = transfer->buffer;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||||
fp_dbg("request is not completed, %d", transfer->status);
|
fp_dbg("request is not completed, %d", transfer->status);
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -288,10 +280,10 @@ static void capture_read_data_cb(struct libusb_transfer *transfer)
|
|||||||
|
|
||||||
switch (transfer->actual_length) {
|
switch (transfer->actual_length) {
|
||||||
case AES2550_STRIP_SIZE:
|
case AES2550_STRIP_SIZE:
|
||||||
r = process_strip_data(ssm, data);
|
r = process_strip_data(ssm, dev, data);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
fp_dbg("Processing strip data failed: %d", r);
|
fp_dbg("Processing strip data failed: %d", r);
|
||||||
fpi_ssm_mark_aborted(ssm, -EPROTO);
|
fpi_ssm_mark_failed(ssm, -EPROTO);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
aesdev->heartbeat_cnt = 0;
|
aesdev->heartbeat_cnt = 0;
|
||||||
@@ -321,79 +313,68 @@ out:
|
|||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void capture_run_state(struct fpi_ssm *ssm)
|
static void capture_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = user_data;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
switch (ssm->cur_state) {
|
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||||
case CAPTURE_WRITE_REQS:
|
case CAPTURE_WRITE_REQS:
|
||||||
{
|
{
|
||||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||||
if (!transfer) {
|
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_OUT, capture_reqs,
|
||||||
return;
|
|
||||||
}
|
|
||||||
libusb_fill_bulk_transfer(transfer, dev->udev, EP_OUT, capture_reqs,
|
|
||||||
sizeof(capture_reqs), capture_reqs_cb, ssm, BULK_TIMEOUT);
|
sizeof(capture_reqs), capture_reqs_cb, ssm, BULK_TIMEOUT);
|
||||||
r = libusb_submit_transfer(transfer);
|
r = libusb_submit_transfer(transfer);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
fpi_ssm_mark_failed(ssm, -ENOMEM);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CAPTURE_READ_DATA:
|
case CAPTURE_READ_DATA:
|
||||||
{
|
{
|
||||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||||
unsigned char *data;
|
unsigned char *data;
|
||||||
|
|
||||||
if (!transfer) {
|
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
data = g_malloc(AES2550_EP_IN_BUF_SIZE);
|
data = g_malloc(AES2550_EP_IN_BUF_SIZE);
|
||||||
libusb_fill_bulk_transfer(transfer, dev->udev, EP_IN, data, AES2550_EP_IN_BUF_SIZE,
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, data, AES2550_EP_IN_BUF_SIZE,
|
||||||
capture_read_data_cb, ssm, BULK_TIMEOUT);
|
capture_read_data_cb, ssm, BULK_TIMEOUT);
|
||||||
|
|
||||||
r = libusb_submit_transfer(transfer);
|
r = libusb_submit_transfer(transfer);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
g_free(data);
|
g_free(data);
|
||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
fpi_ssm_mark_aborted(ssm, r);
|
fpi_ssm_mark_failed(ssm, r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CAPTURE_SET_IDLE:
|
case CAPTURE_SET_IDLE:
|
||||||
{
|
{
|
||||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||||
if (!transfer) {
|
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_OUT, capture_set_idle_reqs,
|
||||||
return;
|
|
||||||
}
|
|
||||||
libusb_fill_bulk_transfer(transfer, dev->udev, EP_OUT, capture_set_idle_reqs,
|
|
||||||
sizeof(capture_set_idle_reqs), capture_set_idle_reqs_cb, ssm, BULK_TIMEOUT);
|
sizeof(capture_set_idle_reqs), capture_set_idle_reqs_cb, ssm, BULK_TIMEOUT);
|
||||||
r = libusb_submit_transfer(transfer);
|
r = libusb_submit_transfer(transfer);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
fpi_ssm_mark_failed(ssm, -ENOMEM);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static void capture_sm_complete(struct fpi_ssm *ssm)
|
static void capture_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = user_data;
|
||||||
struct aes2550_dev *aesdev = dev->priv;
|
struct aes2550_dev *aesdev = FP_INSTANCE_DATA(_dev);
|
||||||
|
|
||||||
fp_dbg("Capture completed");
|
fp_dbg("Capture completed");
|
||||||
if (aesdev->deactivating)
|
if (aesdev->deactivating)
|
||||||
complete_deactivation(dev);
|
complete_deactivation(dev);
|
||||||
else if (ssm->error)
|
else if (fpi_ssm_get_error(ssm))
|
||||||
fpi_imgdev_session_error(dev, ssm->error);
|
fpi_imgdev_session_error(dev, fpi_ssm_get_error(ssm));
|
||||||
else
|
else
|
||||||
start_finger_detection(dev);
|
start_finger_detection(dev);
|
||||||
fpi_ssm_free(ssm);
|
fpi_ssm_free(ssm);
|
||||||
@@ -401,8 +382,8 @@ static void capture_sm_complete(struct fpi_ssm *ssm)
|
|||||||
|
|
||||||
static void start_capture(struct fp_img_dev *dev)
|
static void start_capture(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct aes2550_dev *aesdev = dev->priv;
|
struct aes2550_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
struct fpi_ssm *ssm;
|
fpi_ssm *ssm;
|
||||||
|
|
||||||
if (aesdev->deactivating) {
|
if (aesdev->deactivating) {
|
||||||
complete_deactivation(dev);
|
complete_deactivation(dev);
|
||||||
@@ -410,9 +391,8 @@ static void start_capture(struct fp_img_dev *dev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
aesdev->heartbeat_cnt = 0;
|
aesdev->heartbeat_cnt = 0;
|
||||||
ssm = fpi_ssm_new(dev->dev, capture_run_state, CAPTURE_NUM_STATES);
|
ssm = fpi_ssm_new(FP_DEV(dev), capture_run_state, CAPTURE_NUM_STATES, dev);
|
||||||
fp_dbg("");
|
G_DEBUG_HERE();
|
||||||
ssm->priv = dev;
|
|
||||||
fpi_ssm_start(ssm, capture_sm_complete);
|
fpi_ssm_start(ssm, capture_sm_complete);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -442,161 +422,144 @@ enum activate_states {
|
|||||||
|
|
||||||
static void init_reqs_cb(struct libusb_transfer *transfer)
|
static void init_reqs_cb(struct libusb_transfer *transfer)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
|
|
||||||
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
|
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
|
||||||
(transfer->length == transfer->actual_length)) {
|
(transfer->length == transfer->actual_length)) {
|
||||||
fpi_ssm_next_state(ssm);
|
fpi_ssm_next_state(ssm);
|
||||||
} else {
|
} else {
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
}
|
}
|
||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_read_data_cb(struct libusb_transfer *transfer)
|
static void init_read_data_cb(struct libusb_transfer *transfer)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
|
|
||||||
if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
|
if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
|
||||||
fpi_ssm_next_state(ssm);
|
fpi_ssm_next_state(ssm);
|
||||||
} else {
|
} else {
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
}
|
}
|
||||||
g_free(transfer->buffer);
|
g_free(transfer->buffer);
|
||||||
libusb_free_transfer(transfer);
|
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(struct libusb_transfer *transfer)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
|
|
||||||
if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
|
if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
|
||||||
fpi_ssm_next_state(ssm);
|
fpi_ssm_next_state(ssm);
|
||||||
} else {
|
} else {
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
}
|
}
|
||||||
g_free(transfer->buffer);
|
g_free(transfer->buffer);
|
||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void activate_run_state(struct fpi_ssm *ssm)
|
static void activate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = user_data;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
switch (ssm->cur_state) {
|
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||||
case WRITE_INIT:
|
case WRITE_INIT:
|
||||||
{
|
{
|
||||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||||
if (!transfer) {
|
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_OUT, init_reqs,
|
||||||
return;
|
|
||||||
}
|
|
||||||
libusb_fill_bulk_transfer(transfer, dev->udev, EP_OUT, init_reqs,
|
|
||||||
sizeof(init_reqs), init_reqs_cb, ssm, BULK_TIMEOUT);
|
sizeof(init_reqs), init_reqs_cb, ssm, BULK_TIMEOUT);
|
||||||
r = libusb_submit_transfer(transfer);
|
r = libusb_submit_transfer(transfer);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
fpi_ssm_mark_failed(ssm, -ENOMEM);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case READ_DATA:
|
case READ_DATA:
|
||||||
{
|
{
|
||||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||||
unsigned char *data;
|
unsigned char *data;
|
||||||
|
|
||||||
if (!transfer) {
|
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
data = g_malloc(AES2550_EP_IN_BUF_SIZE);
|
data = g_malloc(AES2550_EP_IN_BUF_SIZE);
|
||||||
libusb_fill_bulk_transfer(transfer, dev->udev, EP_IN, data, AES2550_EP_IN_BUF_SIZE,
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, data, AES2550_EP_IN_BUF_SIZE,
|
||||||
init_read_data_cb, ssm, BULK_TIMEOUT);
|
init_read_data_cb, ssm, BULK_TIMEOUT);
|
||||||
|
|
||||||
r = libusb_submit_transfer(transfer);
|
r = libusb_submit_transfer(transfer);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
g_free(data);
|
g_free(data);
|
||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
fpi_ssm_mark_aborted(ssm, r);
|
fpi_ssm_mark_failed(ssm, r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CALIBRATE:
|
case CALIBRATE:
|
||||||
{
|
{
|
||||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||||
if (!transfer) {
|
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_OUT, calibrate_reqs,
|
||||||
return;
|
|
||||||
}
|
|
||||||
libusb_fill_bulk_transfer(transfer, dev->udev, EP_OUT, calibrate_reqs,
|
|
||||||
sizeof(calibrate_reqs), init_reqs_cb, ssm, BULK_TIMEOUT);
|
sizeof(calibrate_reqs), init_reqs_cb, ssm, BULK_TIMEOUT);
|
||||||
r = libusb_submit_transfer(transfer);
|
r = libusb_submit_transfer(transfer);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
fpi_ssm_mark_failed(ssm, -ENOMEM);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case READ_CALIB_TABLE:
|
case READ_CALIB_TABLE:
|
||||||
{
|
{
|
||||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||||
unsigned char *data;
|
unsigned char *data;
|
||||||
|
|
||||||
if (!transfer) {
|
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
data = g_malloc(AES2550_EP_IN_BUF_SIZE);
|
data = g_malloc(AES2550_EP_IN_BUF_SIZE);
|
||||||
libusb_fill_bulk_transfer(transfer, dev->udev, EP_IN, data, AES2550_EP_IN_BUF_SIZE,
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, data, AES2550_EP_IN_BUF_SIZE,
|
||||||
calibrate_read_data_cb, ssm, BULK_TIMEOUT);
|
calibrate_read_data_cb, ssm, BULK_TIMEOUT);
|
||||||
|
|
||||||
r = libusb_submit_transfer(transfer);
|
r = libusb_submit_transfer(transfer);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
g_free(data);
|
g_free(data);
|
||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
fpi_ssm_mark_aborted(ssm, r);
|
fpi_ssm_mark_failed(ssm, r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void activate_sm_complete(struct fpi_ssm *ssm)
|
static void activate_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = user_data;
|
||||||
fp_dbg("status %d", ssm->error);
|
fp_dbg("status %d", fpi_ssm_get_error(ssm));
|
||||||
fpi_imgdev_activate_complete(dev, ssm->error);
|
fpi_imgdev_activate_complete(dev, fpi_ssm_get_error(ssm));
|
||||||
|
|
||||||
if (!ssm->error)
|
if (!fpi_ssm_get_error(ssm))
|
||||||
start_finger_detection(dev);
|
start_finger_detection(dev);
|
||||||
fpi_ssm_free(ssm);
|
fpi_ssm_free(ssm);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
static int dev_activate(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = fpi_ssm_new(dev->dev, activate_run_state,
|
fpi_ssm *ssm = fpi_ssm_new(FP_DEV(dev), activate_run_state,
|
||||||
ACTIVATE_NUM_STATES);
|
ACTIVATE_NUM_STATES, dev);
|
||||||
ssm->priv = dev;
|
|
||||||
fpi_ssm_start(ssm, activate_sm_complete);
|
fpi_ssm_start(ssm, activate_sm_complete);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dev_deactivate(struct fp_img_dev *dev)
|
static void dev_deactivate(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct aes2550_dev *aesdev = dev->priv;
|
struct aes2550_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
|
||||||
aesdev->deactivating = TRUE;
|
aesdev->deactivating = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void complete_deactivation(struct fp_img_dev *dev)
|
static void complete_deactivation(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct aes2550_dev *aesdev = dev->priv;
|
struct aes2550_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
fp_dbg("");
|
G_DEBUG_HERE();
|
||||||
|
|
||||||
aesdev->deactivating = FALSE;
|
aesdev->deactivating = FALSE;
|
||||||
g_slist_free(aesdev->strips);
|
g_slist_free(aesdev->strips);
|
||||||
@@ -609,22 +572,26 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
|||||||
{
|
{
|
||||||
/* TODO check that device has endpoints we're using */
|
/* TODO check that device has endpoints we're using */
|
||||||
int r;
|
int r;
|
||||||
|
struct aes2550_dev *aes2550_dev;
|
||||||
|
|
||||||
r = libusb_claim_interface(dev->udev, 0);
|
r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
fp_err("could not claim interface 0");
|
fp_err("could not claim interface 0: %s", libusb_error_name(r));
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev->priv = g_malloc0(sizeof(struct aes2550_dev));
|
aes2550_dev = g_malloc0(sizeof(struct aes2550_dev));
|
||||||
|
fp_dev_set_instance_data(FP_DEV(dev), aes2550_dev);
|
||||||
fpi_imgdev_open_complete(dev, 0);
|
fpi_imgdev_open_complete(dev, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dev_deinit(struct fp_img_dev *dev)
|
static void dev_deinit(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
g_free(dev->priv);
|
struct aes2550_dev *aesdev;
|
||||||
libusb_release_interface(dev->udev, 0);
|
aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
g_free(aesdev);
|
||||||
|
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||||
fpi_imgdev_close_complete(dev);
|
fpi_imgdev_close_complete(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,20 +19,20 @@
|
|||||||
|
|
||||||
#define FP_COMPONENT "aes2660"
|
#define FP_COMPONENT "aes2660"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include "drivers_api.h"
|
||||||
|
#include "aeslib.h"
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <libusb.h>
|
|
||||||
|
|
||||||
#include <fp_internal.h>
|
|
||||||
|
|
||||||
#include "aesx660.h"
|
#include "aesx660.h"
|
||||||
#include "aes2660.h"
|
#include "aes2660.h"
|
||||||
#include "driver_ids.h"
|
|
||||||
|
|
||||||
#define FRAME_WIDTH 192
|
#define FRAME_WIDTH 192
|
||||||
|
#define IMAGE_WIDTH (FRAME_WIDTH + (FRAME_WIDTH / 2))
|
||||||
|
|
||||||
|
static struct fpi_frame_asmbl_ctx assembling_ctx = {
|
||||||
|
.frame_width = FRAME_WIDTH,
|
||||||
|
.frame_height = AESX660_FRAME_HEIGHT,
|
||||||
|
.image_width = IMAGE_WIDTH,
|
||||||
|
.get_pixel = aes_get_pixel,
|
||||||
|
};
|
||||||
|
|
||||||
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||||
{
|
{
|
||||||
@@ -40,22 +40,24 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
|||||||
int r;
|
int r;
|
||||||
struct aesX660_dev *aesdev;
|
struct aesX660_dev *aesdev;
|
||||||
|
|
||||||
r = libusb_claim_interface(dev->udev, 0);
|
r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
fp_err("could not claim interface 0");
|
fp_err("could not claim interface 0: %s", libusb_error_name(r));
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev->priv = aesdev = g_malloc0(sizeof(struct aesX660_dev));
|
aesdev = g_malloc0(sizeof(struct aesX660_dev));
|
||||||
|
fp_dev_set_instance_data(FP_DEV(dev), aesdev);
|
||||||
aesdev->buffer = g_malloc0(AES2660_FRAME_SIZE + AESX660_HEADER_SIZE);
|
aesdev->buffer = g_malloc0(AES2660_FRAME_SIZE + AESX660_HEADER_SIZE);
|
||||||
/* No scaling for AES2660 */
|
/* No scaling for AES2660 */
|
||||||
aesdev->init_seqs[0] = aes2660_init_1;
|
aesdev->init_seqs[0] = aes2660_init_1;
|
||||||
aesdev->init_seqs_len[0] = array_n_elements(aes2660_init_1);
|
aesdev->init_seqs_len[0] = G_N_ELEMENTS(aes2660_init_1);
|
||||||
aesdev->init_seqs[1] = aes2660_init_2;
|
aesdev->init_seqs[1] = aes2660_init_2;
|
||||||
aesdev->init_seqs_len[1] = array_n_elements(aes2660_init_2);
|
aesdev->init_seqs_len[1] = G_N_ELEMENTS(aes2660_init_2);
|
||||||
aesdev->start_imaging_cmd = (unsigned char *)aes2660_start_imaging_cmd;
|
aesdev->start_imaging_cmd = (unsigned char *)aes2660_start_imaging_cmd;
|
||||||
aesdev->start_imaging_cmd_len = sizeof(aes2660_start_imaging_cmd);
|
aesdev->start_imaging_cmd_len = sizeof(aes2660_start_imaging_cmd);
|
||||||
aesdev->frame_width = FRAME_WIDTH;
|
aesdev->assembling_ctx = &assembling_ctx;
|
||||||
|
aesdev->extra_img_flags = FP_IMG_PARTIAL;
|
||||||
|
|
||||||
fpi_imgdev_open_complete(dev, 0);
|
fpi_imgdev_open_complete(dev, 0);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -63,10 +65,11 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
|||||||
|
|
||||||
static void dev_deinit(struct fp_img_dev *dev)
|
static void dev_deinit(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct aesX660_dev *aesdev = dev->priv;
|
struct aesX660_dev *aesdev;
|
||||||
|
aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
g_free(aesdev->buffer);
|
g_free(aesdev->buffer);
|
||||||
g_free(aesdev);
|
g_free(aesdev);
|
||||||
libusb_release_interface(dev->udev, 0);
|
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||||
fpi_imgdev_close_complete(dev);
|
fpi_imgdev_close_complete(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,16 +29,9 @@
|
|||||||
|
|
||||||
#define FP_COMPONENT "aes3500"
|
#define FP_COMPONENT "aes3500"
|
||||||
|
|
||||||
#include <errno.h>
|
#include "drivers_api.h"
|
||||||
|
#include "aeslib.h"
|
||||||
#include <glib.h>
|
|
||||||
#include <libusb.h>
|
|
||||||
|
|
||||||
#include <aeslib.h>
|
|
||||||
#include <fp_internal.h>
|
|
||||||
|
|
||||||
#include "aes3k.h"
|
#include "aes3k.h"
|
||||||
#include "driver_ids.h"
|
|
||||||
|
|
||||||
#define DATA_BUFLEN 0x2089
|
#define DATA_BUFLEN 0x2089
|
||||||
|
|
||||||
@@ -129,33 +122,35 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
|||||||
int r;
|
int r;
|
||||||
struct aes3k_dev *aesdev;
|
struct aes3k_dev *aesdev;
|
||||||
|
|
||||||
r = libusb_claim_interface(dev->udev, 0);
|
r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||||
if (r < 0)
|
if (r < 0) {
|
||||||
fp_err("could not claim interface 0");
|
fp_err("could not claim interface 0: %s", libusb_error_name(r));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
aesdev = dev->priv = g_malloc0(sizeof(struct aes3k_dev));
|
aesdev = g_malloc0(sizeof(struct aes3k_dev));
|
||||||
|
fp_dev_set_instance_data(FP_DEV(dev), aesdev);
|
||||||
|
|
||||||
if (!aesdev)
|
if (!aesdev)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
if (r == 0)
|
aesdev->data_buflen = DATA_BUFLEN;
|
||||||
aesdev->data_buflen = DATA_BUFLEN;
|
aesdev->frame_width = FRAME_WIDTH;
|
||||||
aesdev->frame_width = FRAME_WIDTH;
|
aesdev->frame_size = FRAME_SIZE;
|
||||||
aesdev->frame_size = FRAME_SIZE;
|
aesdev->frame_number = FRAME_NUMBER;
|
||||||
aesdev->frame_number = FRAME_NUMBER;
|
aesdev->enlarge_factor = ENLARGE_FACTOR;
|
||||||
aesdev->enlarge_factor = ENLARGE_FACTOR;
|
aesdev->init_reqs = init_reqs;
|
||||||
aesdev->init_reqs = init_reqs;
|
aesdev->init_reqs_len = G_N_ELEMENTS(init_reqs);
|
||||||
aesdev->init_reqs_len = G_N_ELEMENTS(init_reqs);
|
fpi_imgdev_open_complete(dev, 0);
|
||||||
fpi_imgdev_open_complete(dev, 0);
|
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dev_deinit(struct fp_img_dev *dev)
|
static void dev_deinit(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct aes3k_dev *aesdev = dev->priv;
|
struct aes3k_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
g_free(aesdev);
|
g_free(aesdev);
|
||||||
libusb_release_interface(dev->udev, 0);
|
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||||
fpi_imgdev_close_complete(dev);
|
fpi_imgdev_close_complete(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,14 +36,8 @@
|
|||||||
|
|
||||||
#define FP_COMPONENT "aes3k"
|
#define FP_COMPONENT "aes3k"
|
||||||
|
|
||||||
#include <errno.h>
|
#include "drivers_api.h"
|
||||||
|
#include "aeslib.h"
|
||||||
#include <glib.h>
|
|
||||||
#include <libusb.h>
|
|
||||||
|
|
||||||
#include <aeslib.h>
|
|
||||||
#include <fp_internal.h>
|
|
||||||
|
|
||||||
#include "aes3k.h"
|
#include "aes3k.h"
|
||||||
|
|
||||||
#define CTRL_TIMEOUT 1000
|
#define CTRL_TIMEOUT 1000
|
||||||
@@ -69,7 +63,7 @@ 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(struct libusb_transfer *transfer)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = transfer->user_data;
|
struct fp_img_dev *dev = transfer->user_data;
|
||||||
struct aes3k_dev *aesdev = dev->priv;
|
struct aes3k_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
unsigned char *ptr = transfer->buffer;
|
unsigned char *ptr = transfer->buffer;
|
||||||
struct fp_img *tmp;
|
struct fp_img *tmp;
|
||||||
struct fp_img *img;
|
struct fp_img *img;
|
||||||
@@ -100,7 +94,7 @@ static void img_cb(struct libusb_transfer *transfer)
|
|||||||
|
|
||||||
/* 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_img_resize(tmp, aesdev->enlarge_factor, aesdev->enlarge_factor);
|
||||||
fp_img_free(tmp);
|
fp_img_free(tmp);
|
||||||
fpi_imgdev_image_captured(dev, img);
|
fpi_imgdev_image_captured(dev, img);
|
||||||
|
|
||||||
@@ -118,18 +112,13 @@ err:
|
|||||||
|
|
||||||
static void do_capture(struct fp_img_dev *dev)
|
static void do_capture(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct aes3k_dev *aesdev = dev->priv;
|
struct aes3k_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
unsigned char *data;
|
unsigned char *data;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
aesdev->img_trf = libusb_alloc_transfer(0);
|
aesdev->img_trf = fpi_usb_alloc();
|
||||||
if (!aesdev->img_trf) {
|
|
||||||
fpi_imgdev_session_error(dev, -EIO);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
data = g_malloc(aesdev->data_buflen);
|
data = g_malloc(aesdev->data_buflen);
|
||||||
libusb_fill_bulk_transfer(aesdev->img_trf, dev->udev, EP_IN, data,
|
libusb_fill_bulk_transfer(aesdev->img_trf, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, data,
|
||||||
aesdev->data_buflen, img_cb, dev, 0);
|
aesdev->data_buflen, img_cb, dev, 0);
|
||||||
|
|
||||||
r = libusb_submit_transfer(aesdev->img_trf);
|
r = libusb_submit_transfer(aesdev->img_trf);
|
||||||
@@ -148,16 +137,16 @@ static void init_reqs_cb(struct fp_img_dev *dev, int result, void *user_data)
|
|||||||
do_capture(dev);
|
do_capture(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
int aes3k_dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
int aes3k_dev_activate(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct aes3k_dev *aesdev = dev->priv;
|
struct aes3k_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
aes_write_regv(dev, aesdev->init_reqs, aesdev->init_reqs_len, init_reqs_cb, NULL);
|
aes_write_regv(dev, aesdev->init_reqs, aesdev->init_reqs_len, init_reqs_cb, NULL);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void aes3k_dev_deactivate(struct fp_img_dev *dev)
|
void aes3k_dev_deactivate(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct aes3k_dev *aesdev = dev->priv;
|
struct aes3k_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
|
||||||
/* FIXME: should wait for cancellation to complete before returning
|
/* FIXME: should wait for cancellation to complete before returning
|
||||||
* from deactivation, otherwise app may legally exit before we've
|
* from deactivation, otherwise app may legally exit before we've
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ struct aes3k_dev {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
int aes3k_dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state);
|
int aes3k_dev_activate(struct fp_img_dev *dev);
|
||||||
void aes3k_dev_deactivate(struct fp_img_dev *dev);
|
void aes3k_dev_deactivate(struct fp_img_dev *dev);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -26,16 +26,9 @@
|
|||||||
|
|
||||||
#define FP_COMPONENT "aes4000"
|
#define FP_COMPONENT "aes4000"
|
||||||
|
|
||||||
#include <errno.h>
|
#include "drivers_api.h"
|
||||||
|
#include "aeslib.h"
|
||||||
#include <glib.h>
|
|
||||||
#include <libusb.h>
|
|
||||||
|
|
||||||
#include <aeslib.h>
|
|
||||||
#include <fp_internal.h>
|
|
||||||
|
|
||||||
#include "aes3k.h"
|
#include "aes3k.h"
|
||||||
#include "driver_ids.h"
|
|
||||||
|
|
||||||
#define DATA_BUFLEN 0x1259
|
#define DATA_BUFLEN 0x1259
|
||||||
|
|
||||||
@@ -126,33 +119,35 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
|||||||
int r;
|
int r;
|
||||||
struct aes3k_dev *aesdev;
|
struct aes3k_dev *aesdev;
|
||||||
|
|
||||||
r = libusb_claim_interface(dev->udev, 0);
|
r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||||
if (r < 0)
|
if (r < 0) {
|
||||||
fp_err("could not claim interface 0");
|
fp_err("could not claim interface 0: %s", libusb_error_name(r));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
aesdev = dev->priv = g_malloc0(sizeof(struct aes3k_dev));
|
aesdev = g_malloc0(sizeof(struct aes3k_dev));
|
||||||
|
fp_dev_set_instance_data(FP_DEV(dev), aesdev);
|
||||||
|
|
||||||
if (!aesdev)
|
if (!aesdev)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
if (r == 0)
|
aesdev->data_buflen = DATA_BUFLEN;
|
||||||
aesdev->data_buflen = DATA_BUFLEN;
|
aesdev->frame_width = FRAME_WIDTH;
|
||||||
aesdev->frame_width = FRAME_WIDTH;
|
aesdev->frame_size = FRAME_SIZE;
|
||||||
aesdev->frame_size = FRAME_SIZE;
|
aesdev->frame_number = FRAME_NUMBER;
|
||||||
aesdev->frame_number = FRAME_NUMBER;
|
aesdev->enlarge_factor = ENLARGE_FACTOR;
|
||||||
aesdev->enlarge_factor = ENLARGE_FACTOR;
|
aesdev->init_reqs = init_reqs;
|
||||||
aesdev->init_reqs = init_reqs;
|
aesdev->init_reqs_len = G_N_ELEMENTS(init_reqs);
|
||||||
aesdev->init_reqs_len = G_N_ELEMENTS(init_reqs);
|
fpi_imgdev_open_complete(dev, 0);
|
||||||
fpi_imgdev_open_complete(dev, 0);
|
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dev_deinit(struct fp_img_dev *dev)
|
static void dev_deinit(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct aes3k_dev *aesdev = dev->priv;
|
struct aes3k_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
g_free(aesdev);
|
g_free(aesdev);
|
||||||
libusb_release_interface(dev->udev, 0);
|
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||||
fpi_imgdev_close_complete(dev);
|
fpi_imgdev_close_complete(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
177
libfprint/drivers/aeslib.c
Normal file
177
libfprint/drivers/aeslib.c
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
/*
|
||||||
|
* 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 <glib.h>
|
||||||
|
|
||||||
|
#include "fpi-usb.h"
|
||||||
|
#include "fpi-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);
|
||||||
|
g_free(wdata);
|
||||||
|
} else if (transfer->length != transfer->actual_length) {
|
||||||
|
wdata->callback(wdata->imgdev, -EPROTO, wdata->user_data);
|
||||||
|
g_free(wdata);
|
||||||
|
} 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 = fpi_usb_alloc();
|
||||||
|
int r;
|
||||||
|
|
||||||
|
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, FP_DEV(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);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = do_write_regv(wdata, upper_bound);
|
||||||
|
if (r < 0) {
|
||||||
|
wdata->callback(wdata->imgdev, r, wdata->user_data);
|
||||||
|
g_free(wdata);
|
||||||
|
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;
|
||||||
|
|
||||||
|
fp_dbg("write %d regs", num_regs);
|
||||||
|
wdata = g_malloc(sizeof(*wdata));
|
||||||
|
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;
|
||||||
|
}
|
||||||
@@ -20,18 +20,15 @@
|
|||||||
#ifndef __AESLIB_H__
|
#ifndef __AESLIB_H__
|
||||||
#define __AESLIB_H__
|
#define __AESLIB_H__
|
||||||
|
|
||||||
#include <fp_internal.h>
|
#include <fprint.h>
|
||||||
|
|
||||||
struct aes_regwrite {
|
struct aes_regwrite {
|
||||||
unsigned char reg;
|
unsigned char reg;
|
||||||
unsigned char value;
|
unsigned char value;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct aes_stripe {
|
struct fpi_frame;
|
||||||
int delta_x;
|
struct fpi_frame_asmbl_ctx;
|
||||||
int delta_y;
|
|
||||||
unsigned char data[0];
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef void (*aes_write_regv_cb)(struct fp_img_dev *dev, int result,
|
typedef void (*aes_write_regv_cb)(struct fp_img_dev *dev, int result,
|
||||||
void *user_data);
|
void *user_data);
|
||||||
@@ -39,12 +36,10 @@ typedef void (*aes_write_regv_cb)(struct fp_img_dev *dev, int result,
|
|||||||
void aes_write_regv(struct fp_img_dev *dev, const struct aes_regwrite *regs,
|
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);
|
unsigned int num_regs, aes_write_regv_cb callback, void *user_data);
|
||||||
|
|
||||||
unsigned int aes_calc_delta(GSList *stripes, size_t stripes_len,
|
unsigned char aes_get_pixel(struct fpi_frame_asmbl_ctx *ctx,
|
||||||
unsigned int frame_width, unsigned int frame_height,
|
struct fpi_frame *frame,
|
||||||
gboolean reverse);
|
unsigned int x,
|
||||||
|
unsigned int y);
|
||||||
struct fp_img *aes_assemble(GSList *stripes, size_t stripes_len,
|
|
||||||
unsigned int frame_width, unsigned int frame_height, unsigned int img_width);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -23,16 +23,8 @@
|
|||||||
|
|
||||||
#define FP_COMPONENT "aesX660"
|
#define FP_COMPONENT "aesX660"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include "drivers_api.h"
|
||||||
|
#include "aeslib.h"
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <libusb.h>
|
|
||||||
|
|
||||||
#include <aeslib.h>
|
|
||||||
#include <fp_internal.h>
|
|
||||||
|
|
||||||
#include "aesx660.h"
|
#include "aesx660.h"
|
||||||
|
|
||||||
static void start_capture(struct fp_img_dev *dev);
|
static void start_capture(struct fp_img_dev *dev);
|
||||||
@@ -41,54 +33,59 @@ static void complete_deactivation(struct fp_img_dev *dev);
|
|||||||
#define EP_IN (1 | LIBUSB_ENDPOINT_IN)
|
#define EP_IN (1 | LIBUSB_ENDPOINT_IN)
|
||||||
#define EP_OUT (2 | LIBUSB_ENDPOINT_OUT)
|
#define EP_OUT (2 | LIBUSB_ENDPOINT_OUT)
|
||||||
#define BULK_TIMEOUT 4000
|
#define BULK_TIMEOUT 4000
|
||||||
#define FRAME_HEIGHT 8
|
#define FRAME_HEIGHT AESX660_FRAME_HEIGHT
|
||||||
|
|
||||||
#define min(a, b) (((a) < (b)) ? (a) : (b))
|
#define ID_LEN 8
|
||||||
|
#define INIT_LEN 4
|
||||||
|
#define CALIBRATE_DATA_LEN 4
|
||||||
|
#define FINGER_DET_DATA_LEN 4
|
||||||
|
|
||||||
static void aesX660_send_cmd_timeout(struct fpi_ssm *ssm, const unsigned char *cmd,
|
static void
|
||||||
size_t cmd_len, libusb_transfer_cb_fn callback, int timeout)
|
aesX660_send_cmd_timeout(fpi_ssm *ssm,
|
||||||
|
struct fp_dev *_dev,
|
||||||
|
const unsigned char *cmd,
|
||||||
|
size_t cmd_len,
|
||||||
|
libusb_transfer_cb_fn callback,
|
||||||
|
int timeout)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = FP_IMG_DEV(_dev);
|
||||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (!transfer) {
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_OUT,
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
libusb_fill_bulk_transfer(transfer, dev->udev, EP_OUT,
|
|
||||||
(unsigned char *)cmd, cmd_len,
|
(unsigned char *)cmd, cmd_len,
|
||||||
callback, ssm, timeout);
|
callback, ssm, timeout);
|
||||||
r = libusb_submit_transfer(transfer);
|
r = libusb_submit_transfer(transfer);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
fp_dbg("failed to submit transfer\n");
|
fp_dbg("failed to submit transfer\n");
|
||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
fpi_ssm_mark_failed(ssm, -ENOMEM);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void aesX660_send_cmd(struct fpi_ssm *ssm, const unsigned char *cmd,
|
static void
|
||||||
size_t cmd_len, libusb_transfer_cb_fn callback)
|
aesX660_send_cmd(fpi_ssm *ssm,
|
||||||
|
struct fp_dev *dev,
|
||||||
|
const unsigned char *cmd,
|
||||||
|
size_t cmd_len,
|
||||||
|
libusb_transfer_cb_fn callback)
|
||||||
{
|
{
|
||||||
return aesX660_send_cmd_timeout(ssm, cmd, cmd_len, callback, BULK_TIMEOUT);
|
return aesX660_send_cmd_timeout(ssm, dev, cmd, cmd_len, callback, BULK_TIMEOUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void aesX660_read_response(struct fpi_ssm *ssm, size_t buf_len,
|
static void
|
||||||
libusb_transfer_cb_fn callback)
|
aesX660_read_response(fpi_ssm *ssm,
|
||||||
|
struct fp_dev *_dev,
|
||||||
|
size_t buf_len,
|
||||||
|
libusb_transfer_cb_fn callback)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = FP_IMG_DEV(_dev);
|
||||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||||
unsigned char *data;
|
unsigned char *data;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (!transfer) {
|
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
data = g_malloc(buf_len);
|
data = g_malloc(buf_len);
|
||||||
libusb_fill_bulk_transfer(transfer, dev->udev, EP_IN,
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN,
|
||||||
data, buf_len,
|
data, buf_len,
|
||||||
callback, ssm, BULK_TIMEOUT);
|
callback, ssm, BULK_TIMEOUT);
|
||||||
|
|
||||||
@@ -97,13 +94,13 @@ static void aesX660_read_response(struct fpi_ssm *ssm, size_t buf_len,
|
|||||||
fp_dbg("Failed to submit rx transfer: %d\n", r);
|
fp_dbg("Failed to submit rx transfer: %d\n", r);
|
||||||
g_free(data);
|
g_free(data);
|
||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
fpi_ssm_mark_aborted(ssm, r);
|
fpi_ssm_mark_failed(ssm, r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void aesX660_send_cmd_cb(struct libusb_transfer *transfer)
|
static void aesX660_send_cmd_cb(struct libusb_transfer *transfer)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
|
|
||||||
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
|
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
|
||||||
(transfer->length == transfer->actual_length)) {
|
(transfer->length == transfer->actual_length)) {
|
||||||
@@ -111,25 +108,25 @@ static void aesX660_send_cmd_cb(struct libusb_transfer *transfer)
|
|||||||
} else {
|
} else {
|
||||||
fp_dbg("tx transfer status: %d, actual_len: %.4x\n",
|
fp_dbg("tx transfer status: %d, actual_len: %.4x\n",
|
||||||
transfer->status, transfer->actual_length);
|
transfer->status, transfer->actual_length);
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
}
|
}
|
||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void aesX660_read_calibrate_data_cb(struct libusb_transfer *transfer)
|
static void aesX660_read_calibrate_data_cb(struct libusb_transfer *transfer)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
unsigned char *data = transfer->buffer;
|
unsigned char *data = transfer->buffer;
|
||||||
|
|
||||||
if ((transfer->status != LIBUSB_TRANSFER_COMPLETED) ||
|
if ((transfer->status != LIBUSB_TRANSFER_COMPLETED) ||
|
||||||
(transfer->length != transfer->actual_length)) {
|
(transfer->length != transfer->actual_length)) {
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
/* Calibrate response was read correctly? */
|
/* Calibrate response was read correctly? */
|
||||||
if (data[AESX660_RESPONSE_TYPE_OFFSET] != AESX660_CALIBRATE_RESPONSE) {
|
if (data[AESX660_RESPONSE_TYPE_OFFSET] != AESX660_CALIBRATE_RESPONSE) {
|
||||||
fp_dbg("Bogus calibrate response: %.2x\n", data[0]);
|
fp_dbg("Bogus calibrate response: %.2x\n", data[0]);
|
||||||
fpi_ssm_mark_aborted(ssm, -EPROTO);
|
fpi_ssm_mark_failed(ssm, -EPROTO);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,9 +148,9 @@ enum finger_det_states {
|
|||||||
|
|
||||||
static void finger_det_read_fd_data_cb(struct libusb_transfer *transfer)
|
static void finger_det_read_fd_data_cb(struct libusb_transfer *transfer)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
||||||
struct aesX660_dev *aesdev = dev->priv;
|
struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
unsigned char *data = transfer->buffer;
|
unsigned char *data = transfer->buffer;
|
||||||
|
|
||||||
aesdev->fd_data_transfer = NULL;
|
aesdev->fd_data_transfer = NULL;
|
||||||
@@ -167,13 +164,13 @@ static void finger_det_read_fd_data_cb(struct libusb_transfer *transfer)
|
|||||||
if ((transfer->status != LIBUSB_TRANSFER_COMPLETED) ||
|
if ((transfer->status != LIBUSB_TRANSFER_COMPLETED) ||
|
||||||
(transfer->length != transfer->actual_length)) {
|
(transfer->length != transfer->actual_length)) {
|
||||||
fp_dbg("Failed to read FD data\n");
|
fp_dbg("Failed to read FD data\n");
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data[AESX660_RESPONSE_TYPE_OFFSET] != AESX660_FINGER_DET_RESPONSE) {
|
if (data[AESX660_RESPONSE_TYPE_OFFSET] != AESX660_FINGER_DET_RESPONSE) {
|
||||||
fp_dbg("Bogus FD response: %.2x\n", data[0]);
|
fp_dbg("Bogus FD response: %.2x\n", data[0]);
|
||||||
fpi_ssm_mark_aborted(ssm, -EPROTO);
|
fpi_ssm_mark_failed(ssm, -EPROTO);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,22 +189,22 @@ out:
|
|||||||
|
|
||||||
static void finger_det_set_idle_cmd_cb(struct libusb_transfer *transfer)
|
static void finger_det_set_idle_cmd_cb(struct libusb_transfer *transfer)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
|
|
||||||
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
|
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
|
||||||
(transfer->length == transfer->actual_length)) {
|
(transfer->length == transfer->actual_length)) {
|
||||||
fpi_ssm_mark_completed(ssm);
|
fpi_ssm_mark_completed(ssm);
|
||||||
} else {
|
} else {
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
}
|
}
|
||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void finger_det_sm_complete(struct fpi_ssm *ssm)
|
static void finger_det_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = user_data;
|
||||||
struct aesX660_dev *aesdev = dev->priv;
|
struct aesX660_dev *aesdev = FP_INSTANCE_DATA(_dev);
|
||||||
int err = ssm->error;
|
int err = fpi_ssm_get_error(ssm);
|
||||||
|
|
||||||
fp_dbg("Finger detection completed");
|
fp_dbg("Finger detection completed");
|
||||||
fpi_imgdev_report_finger_status(dev, TRUE);
|
fpi_imgdev_report_finger_status(dev, TRUE);
|
||||||
@@ -223,23 +220,22 @@ static void finger_det_sm_complete(struct fpi_ssm *ssm)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void finger_det_run_state(struct fpi_ssm *ssm)
|
static void finger_det_run_state(fpi_ssm *ssm, struct fp_dev *dev, void *user_data)
|
||||||
{
|
{
|
||||||
switch (ssm->cur_state) {
|
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||||
case FINGER_DET_SEND_LED_CMD:
|
case FINGER_DET_SEND_LED_CMD:
|
||||||
aesX660_send_cmd(ssm, led_blink_cmd, sizeof(led_blink_cmd),
|
aesX660_send_cmd(ssm, dev, led_blink_cmd, sizeof(led_blink_cmd),
|
||||||
aesX660_send_cmd_cb);
|
aesX660_send_cmd_cb);
|
||||||
break;
|
break;
|
||||||
case FINGER_DET_SEND_FD_CMD:
|
case FINGER_DET_SEND_FD_CMD:
|
||||||
aesX660_send_cmd_timeout(ssm, wait_for_finger_cmd, sizeof(wait_for_finger_cmd),
|
aesX660_send_cmd_timeout(ssm, dev, wait_for_finger_cmd, sizeof(wait_for_finger_cmd),
|
||||||
aesX660_send_cmd_cb, 0);
|
aesX660_send_cmd_cb, 0);
|
||||||
break;
|
break;
|
||||||
case FINGER_DET_READ_FD_DATA:
|
case FINGER_DET_READ_FD_DATA:
|
||||||
/* Should return 4 byte of response */
|
aesX660_read_response(ssm, dev, FINGER_DET_DATA_LEN, finger_det_read_fd_data_cb);
|
||||||
aesX660_read_response(ssm, 4, finger_det_read_fd_data_cb);
|
|
||||||
break;
|
break;
|
||||||
case FINGER_DET_SET_IDLE:
|
case FINGER_DET_SET_IDLE:
|
||||||
aesX660_send_cmd(ssm, set_idle_cmd, sizeof(set_idle_cmd),
|
aesX660_send_cmd(ssm, dev, set_idle_cmd, sizeof(set_idle_cmd),
|
||||||
finger_det_set_idle_cmd_cb);
|
finger_det_set_idle_cmd_cb);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -247,16 +243,15 @@ static void finger_det_run_state(struct fpi_ssm *ssm)
|
|||||||
|
|
||||||
static void start_finger_detection(struct fp_img_dev *dev)
|
static void start_finger_detection(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm;
|
fpi_ssm *ssm;
|
||||||
struct aesX660_dev *aesdev = dev->priv;
|
struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
|
||||||
if (aesdev->deactivating) {
|
if (aesdev->deactivating) {
|
||||||
complete_deactivation(dev);
|
complete_deactivation(dev);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssm = fpi_ssm_new(dev->dev, finger_det_run_state, FINGER_DET_NUM_STATES);
|
ssm = fpi_ssm_new(FP_DEV(dev), finger_det_run_state, FINGER_DET_NUM_STATES, dev);
|
||||||
ssm->priv = dev;
|
|
||||||
fpi_ssm_start(ssm, finger_det_sm_complete);
|
fpi_ssm_start(ssm, finger_det_sm_complete);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -271,14 +266,13 @@ enum capture_states {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* Returns number of processed bytes */
|
/* Returns number of processed bytes */
|
||||||
static int process_stripe_data(struct fpi_ssm *ssm, unsigned char *data)
|
static int process_stripe_data(fpi_ssm *ssm, struct fp_img_dev *dev, unsigned char *data)
|
||||||
{
|
{
|
||||||
struct aes_stripe *stripe;
|
struct fpi_frame *stripe;
|
||||||
unsigned char *stripdata;
|
unsigned char *stripdata;
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
struct aesX660_dev *aesdev = dev->priv;
|
|
||||||
|
|
||||||
stripe = g_malloc(aesdev->frame_width * FRAME_HEIGHT / 2 + sizeof(struct aes_stripe)); /* 4 bpp */
|
stripe = g_malloc(aesdev->assembling_ctx->frame_width * FRAME_HEIGHT / 2 + sizeof(struct fpi_frame)); /* 4 bpp */
|
||||||
stripdata = stripe->data;
|
stripdata = stripe->data;
|
||||||
|
|
||||||
fp_dbg("Processing frame %.2x %.2x", data[AESX660_IMAGE_OK_OFFSET],
|
fp_dbg("Processing frame %.2x %.2x", data[AESX660_IMAGE_OK_OFFSET],
|
||||||
@@ -289,30 +283,30 @@ static int process_stripe_data(struct fpi_ssm *ssm, unsigned char *data)
|
|||||||
fp_dbg("Offset to previous frame: %d %d", stripe->delta_x, stripe->delta_y);
|
fp_dbg("Offset to previous frame: %d %d", stripe->delta_x, stripe->delta_y);
|
||||||
|
|
||||||
if (data[AESX660_IMAGE_OK_OFFSET] == AESX660_IMAGE_OK) {
|
if (data[AESX660_IMAGE_OK_OFFSET] == AESX660_IMAGE_OK) {
|
||||||
memcpy(stripdata, data + AESX660_IMAGE_OFFSET, aesdev->frame_width * FRAME_HEIGHT / 2);
|
memcpy(stripdata, data + AESX660_IMAGE_OFFSET, aesdev->assembling_ctx->frame_width * FRAME_HEIGHT / 2);
|
||||||
|
|
||||||
aesdev->strips = g_slist_prepend(aesdev->strips, stripe);
|
aesdev->strips = g_slist_prepend(aesdev->strips, stripe);
|
||||||
aesdev->strips_len++;
|
aesdev->strips_len++;
|
||||||
return (data[AESX660_LAST_FRAME_OFFSET] & AESX660_LAST_FRAME_BIT);
|
return (data[AESX660_LAST_FRAME_OFFSET] & AESX660_LAST_FRAME_BIT);
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_free(stripe);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void capture_set_idle_cmd_cb(struct libusb_transfer *transfer)
|
static void capture_set_idle_cmd_cb(struct libusb_transfer *transfer)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
||||||
struct aesX660_dev *aesdev = dev->priv;
|
struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
|
||||||
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
|
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
|
||||||
(transfer->length == transfer->actual_length)) {
|
(transfer->length == transfer->actual_length)) {
|
||||||
struct fp_img *img;
|
struct fp_img *img;
|
||||||
|
|
||||||
aesdev->strips = g_slist_reverse(aesdev->strips);
|
aesdev->strips = g_slist_reverse(aesdev->strips);
|
||||||
img = aes_assemble(aesdev->strips, aesdev->strips_len,
|
img = fpi_assemble_frames(aesdev->assembling_ctx, aesdev->strips, aesdev->strips_len);
|
||||||
aesdev->frame_width, FRAME_HEIGHT, aesdev->frame_width + aesdev->frame_width / 2);
|
img->flags |= aesdev->extra_img_flags;
|
||||||
g_slist_foreach(aesdev->strips, (GFunc) g_free, NULL);
|
g_slist_foreach(aesdev->strips, (GFunc) g_free, NULL);
|
||||||
g_slist_free(aesdev->strips);
|
g_slist_free(aesdev->strips);
|
||||||
aesdev->strips = NULL;
|
aesdev->strips = NULL;
|
||||||
@@ -321,46 +315,46 @@ static void capture_set_idle_cmd_cb(struct libusb_transfer *transfer)
|
|||||||
fpi_imgdev_report_finger_status(dev, FALSE);
|
fpi_imgdev_report_finger_status(dev, FALSE);
|
||||||
fpi_ssm_mark_completed(ssm);
|
fpi_ssm_mark_completed(ssm);
|
||||||
} else {
|
} else {
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
}
|
}
|
||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void capture_read_stripe_data_cb(struct libusb_transfer *transfer)
|
static void capture_read_stripe_data_cb(struct libusb_transfer *transfer)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
||||||
struct aesX660_dev *aesdev = dev->priv;
|
struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
unsigned char *data = transfer->buffer;
|
unsigned char *data = transfer->buffer;
|
||||||
int finger_missing = 0;
|
int finger_missing = 0;
|
||||||
size_t copied, actual_len = transfer->actual_length;
|
size_t copied, actual_len = transfer->actual_length;
|
||||||
|
|
||||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
fp_dbg("Got %d bytes of data", actual_len);
|
fp_dbg("Got %lu bytes of data", actual_len);
|
||||||
do {
|
do {
|
||||||
copied = min(aesdev->buffer_max - aesdev->buffer_size, actual_len);
|
copied = MIN(aesdev->buffer_max - aesdev->buffer_size, actual_len);
|
||||||
memcpy(aesdev->buffer + aesdev->buffer_size,
|
memcpy(aesdev->buffer + aesdev->buffer_size,
|
||||||
data,
|
data,
|
||||||
copied);
|
copied);
|
||||||
actual_len -= copied;
|
actual_len -= copied;
|
||||||
data += copied;
|
data += copied;
|
||||||
aesdev->buffer_size += copied;
|
aesdev->buffer_size += copied;
|
||||||
fp_dbg("Copied %.4x bytes into internal buffer",
|
fp_dbg("Copied %.4lx bytes into internal buffer",
|
||||||
copied);
|
copied);
|
||||||
if (aesdev->buffer_size == aesdev->buffer_max) {
|
if (aesdev->buffer_size == aesdev->buffer_max) {
|
||||||
if (aesdev->buffer_max == AESX660_HEADER_SIZE) {
|
if (aesdev->buffer_max == AESX660_HEADER_SIZE) {
|
||||||
aesdev->buffer_max = aesdev->buffer[AESX660_RESPONSE_SIZE_LSB_OFFSET] +
|
aesdev->buffer_max = aesdev->buffer[AESX660_RESPONSE_SIZE_LSB_OFFSET] +
|
||||||
(aesdev->buffer[AESX660_RESPONSE_SIZE_MSB_OFFSET] << 8) + AESX660_HEADER_SIZE;
|
(aesdev->buffer[AESX660_RESPONSE_SIZE_MSB_OFFSET] << 8) + AESX660_HEADER_SIZE;
|
||||||
fp_dbg("Got frame, type %.2x size %.4x",
|
fp_dbg("Got frame, type %.2x size %.4lx",
|
||||||
aesdev->buffer[AESX660_RESPONSE_TYPE_OFFSET],
|
aesdev->buffer[AESX660_RESPONSE_TYPE_OFFSET],
|
||||||
aesdev->buffer_max);
|
aesdev->buffer_max);
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
finger_missing |= process_stripe_data(ssm, aesdev->buffer);
|
finger_missing |= process_stripe_data(ssm, dev, aesdev->buffer);
|
||||||
aesdev->buffer_max = AESX660_HEADER_SIZE;
|
aesdev->buffer_max = AESX660_HEADER_SIZE;
|
||||||
aesdev->buffer_size = 0;
|
aesdev->buffer_size = 0;
|
||||||
}
|
}
|
||||||
@@ -379,40 +373,39 @@ out:
|
|||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void capture_run_state(struct fpi_ssm *ssm)
|
static void capture_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct aesX660_dev *aesdev = FP_INSTANCE_DATA(_dev);
|
||||||
struct aesX660_dev *aesdev = dev->priv;
|
|
||||||
|
|
||||||
switch (ssm->cur_state) {
|
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||||
case CAPTURE_SEND_LED_CMD:
|
case CAPTURE_SEND_LED_CMD:
|
||||||
aesX660_send_cmd(ssm, led_solid_cmd, sizeof(led_solid_cmd),
|
aesX660_send_cmd(ssm, _dev, led_solid_cmd, sizeof(led_solid_cmd),
|
||||||
aesX660_send_cmd_cb);
|
aesX660_send_cmd_cb);
|
||||||
break;
|
break;
|
||||||
case CAPTURE_SEND_CAPTURE_CMD:
|
case CAPTURE_SEND_CAPTURE_CMD:
|
||||||
aesdev->buffer_size = 0;
|
aesdev->buffer_size = 0;
|
||||||
aesdev->buffer_max = AESX660_HEADER_SIZE;
|
aesdev->buffer_max = AESX660_HEADER_SIZE;
|
||||||
aesX660_send_cmd(ssm, aesdev->start_imaging_cmd,
|
aesX660_send_cmd(ssm, _dev, aesdev->start_imaging_cmd,
|
||||||
aesdev->start_imaging_cmd_len,
|
aesdev->start_imaging_cmd_len,
|
||||||
aesX660_send_cmd_cb);
|
aesX660_send_cmd_cb);
|
||||||
break;
|
break;
|
||||||
case CAPTURE_READ_STRIPE_DATA:
|
case CAPTURE_READ_STRIPE_DATA:
|
||||||
aesX660_read_response(ssm, AESX660_BULK_TRANSFER_SIZE,
|
aesX660_read_response(ssm, _dev, AESX660_BULK_TRANSFER_SIZE,
|
||||||
capture_read_stripe_data_cb);
|
capture_read_stripe_data_cb);
|
||||||
break;
|
break;
|
||||||
case CAPTURE_SET_IDLE:
|
case CAPTURE_SET_IDLE:
|
||||||
fp_dbg("Got %d frames\n", aesdev->strips_len);
|
fp_dbg("Got %lu frames\n", aesdev->strips_len);
|
||||||
aesX660_send_cmd(ssm, set_idle_cmd, sizeof(set_idle_cmd),
|
aesX660_send_cmd(ssm, _dev, set_idle_cmd, sizeof(set_idle_cmd),
|
||||||
capture_set_idle_cmd_cb);
|
capture_set_idle_cmd_cb);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void capture_sm_complete(struct fpi_ssm *ssm)
|
static void capture_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = user_data;
|
||||||
struct aesX660_dev *aesdev = dev->priv;
|
struct aesX660_dev *aesdev = FP_INSTANCE_DATA(_dev);
|
||||||
int err = ssm->error;
|
int err = fpi_ssm_get_error(ssm);
|
||||||
|
|
||||||
fp_dbg("Capture completed");
|
fp_dbg("Capture completed");
|
||||||
fpi_ssm_free(ssm);
|
fpi_ssm_free(ssm);
|
||||||
@@ -427,17 +420,16 @@ static void capture_sm_complete(struct fpi_ssm *ssm)
|
|||||||
|
|
||||||
static void start_capture(struct fp_img_dev *dev)
|
static void start_capture(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct aesX660_dev *aesdev = dev->priv;
|
struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
struct fpi_ssm *ssm;
|
fpi_ssm *ssm;
|
||||||
|
|
||||||
if (aesdev->deactivating) {
|
if (aesdev->deactivating) {
|
||||||
complete_deactivation(dev);
|
complete_deactivation(dev);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssm = fpi_ssm_new(dev->dev, capture_run_state, CAPTURE_NUM_STATES);
|
ssm = fpi_ssm_new(FP_DEV(dev), capture_run_state, CAPTURE_NUM_STATES, dev);
|
||||||
fp_dbg("");
|
G_DEBUG_HERE();
|
||||||
ssm->priv = dev;
|
|
||||||
fpi_ssm_start(ssm, capture_sm_complete);
|
fpi_ssm_start(ssm, capture_sm_complete);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -456,15 +448,15 @@ enum activate_states {
|
|||||||
|
|
||||||
static void activate_read_id_cb(struct libusb_transfer *transfer)
|
static void activate_read_id_cb(struct libusb_transfer *transfer)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
||||||
struct aesX660_dev *aesdev = dev->priv;
|
struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
unsigned char *data = transfer->buffer;
|
unsigned char *data = transfer->buffer;
|
||||||
|
|
||||||
if ((transfer->status != LIBUSB_TRANSFER_COMPLETED) ||
|
if ((transfer->status != LIBUSB_TRANSFER_COMPLETED) ||
|
||||||
(transfer->length != transfer->actual_length)) {
|
(transfer->length != transfer->actual_length)) {
|
||||||
fp_dbg("read_id cmd failed\n");
|
fp_dbg("read_id cmd failed\n");
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
/* ID was read correctly */
|
/* ID was read correctly */
|
||||||
@@ -473,7 +465,7 @@ static void activate_read_id_cb(struct libusb_transfer *transfer)
|
|||||||
data[4], data[3], data[5], data[6], data[7]);
|
data[4], data[3], data[5], data[6], data[7]);
|
||||||
} else {
|
} else {
|
||||||
fp_dbg("Bogus read ID response: %.2x\n", data[AESX660_RESPONSE_TYPE_OFFSET]);
|
fp_dbg("Bogus read ID response: %.2x\n", data[AESX660_RESPONSE_TYPE_OFFSET]);
|
||||||
fpi_ssm_mark_aborted(ssm, -EPROTO);
|
fpi_ssm_mark_failed(ssm, -EPROTO);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -495,7 +487,7 @@ static void activate_read_id_cb(struct libusb_transfer *transfer)
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fp_dbg("Failed to init device! init status: %.2x\n", data[7]);
|
fp_dbg("Failed to init device! init status: %.2x\n", data[7]);
|
||||||
fpi_ssm_mark_aborted(ssm, -EPROTO);
|
fpi_ssm_mark_failed(ssm, -EPROTO);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -507,9 +499,9 @@ out:
|
|||||||
|
|
||||||
static void activate_read_init_cb(struct libusb_transfer *transfer)
|
static void activate_read_init_cb(struct libusb_transfer *transfer)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
||||||
struct aesX660_dev *aesdev = dev->priv;
|
struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
unsigned char *data = transfer->buffer;
|
unsigned char *data = transfer->buffer;
|
||||||
|
|
||||||
fp_dbg("read_init_cb\n");
|
fp_dbg("read_init_cb\n");
|
||||||
@@ -517,14 +509,14 @@ static void activate_read_init_cb(struct libusb_transfer *transfer)
|
|||||||
if ((transfer->status != LIBUSB_TRANSFER_COMPLETED) ||
|
if ((transfer->status != LIBUSB_TRANSFER_COMPLETED) ||
|
||||||
(transfer->length != transfer->actual_length)) {
|
(transfer->length != transfer->actual_length)) {
|
||||||
fp_dbg("read_init transfer status: %d, actual_len: %d\n", transfer->status, transfer->actual_length);
|
fp_dbg("read_init transfer status: %d, actual_len: %d\n", transfer->status, transfer->actual_length);
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
/* ID was read correctly */
|
/* ID was read correctly */
|
||||||
if (data[0] != 0x42 || data[3] != 0x01) {
|
if (data[0] != 0x42 || data[3] != 0x01) {
|
||||||
fp_dbg("Bogus read init response: %.2x %.2x\n", data[0],
|
fp_dbg("Bogus read init response: %.2x %.2x\n", data[0],
|
||||||
data[3]);
|
data[3]);
|
||||||
fpi_ssm_mark_aborted(ssm, -EPROTO);
|
fpi_ssm_mark_failed(ssm, -EPROTO);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
aesdev->init_cmd_idx++;
|
aesdev->init_cmd_idx++;
|
||||||
@@ -542,56 +534,53 @@ out:
|
|||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void activate_run_state(struct fpi_ssm *ssm)
|
static void activate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = user_data;
|
||||||
struct aesX660_dev *aesdev = dev->priv;
|
struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
|
||||||
switch (ssm->cur_state) {
|
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||||
case ACTIVATE_SET_IDLE:
|
case ACTIVATE_SET_IDLE:
|
||||||
aesdev->init_seq_idx = 0;
|
aesdev->init_seq_idx = 0;
|
||||||
fp_dbg("Activate: set idle\n");
|
fp_dbg("Activate: set idle\n");
|
||||||
aesX660_send_cmd(ssm, set_idle_cmd, sizeof(set_idle_cmd),
|
aesX660_send_cmd(ssm, _dev, set_idle_cmd, sizeof(set_idle_cmd),
|
||||||
aesX660_send_cmd_cb);
|
aesX660_send_cmd_cb);
|
||||||
break;
|
break;
|
||||||
case ACTIVATE_SEND_READ_ID_CMD:
|
case ACTIVATE_SEND_READ_ID_CMD:
|
||||||
fp_dbg("Activate: read ID\n");
|
fp_dbg("Activate: read ID\n");
|
||||||
aesX660_send_cmd(ssm, read_id_cmd, sizeof(read_id_cmd),
|
aesX660_send_cmd(ssm, _dev, read_id_cmd, sizeof(read_id_cmd),
|
||||||
aesX660_send_cmd_cb);
|
aesX660_send_cmd_cb);
|
||||||
break;
|
break;
|
||||||
case ACTIVATE_READ_ID:
|
case ACTIVATE_READ_ID:
|
||||||
/* Should return 8-byte response */
|
aesX660_read_response(ssm, _dev, ID_LEN, activate_read_id_cb);
|
||||||
aesX660_read_response(ssm, 8, activate_read_id_cb);
|
|
||||||
break;
|
break;
|
||||||
case ACTIVATE_SEND_INIT_CMD:
|
case ACTIVATE_SEND_INIT_CMD:
|
||||||
fp_dbg("Activate: send init seq #%d cmd #%d\n",
|
fp_dbg("Activate: send init seq #%d cmd #%d\n",
|
||||||
aesdev->init_seq_idx,
|
aesdev->init_seq_idx,
|
||||||
aesdev->init_cmd_idx);
|
aesdev->init_cmd_idx);
|
||||||
aesX660_send_cmd(ssm,
|
aesX660_send_cmd(ssm, _dev,
|
||||||
aesdev->init_seq[aesdev->init_cmd_idx].cmd,
|
aesdev->init_seq[aesdev->init_cmd_idx].cmd,
|
||||||
aesdev->init_seq[aesdev->init_cmd_idx].len,
|
aesdev->init_seq[aesdev->init_cmd_idx].len,
|
||||||
aesX660_send_cmd_cb);
|
aesX660_send_cmd_cb);
|
||||||
break;
|
break;
|
||||||
case ACTIVATE_READ_INIT_RESPONSE:
|
case ACTIVATE_READ_INIT_RESPONSE:
|
||||||
fp_dbg("Activate: read init response\n");
|
fp_dbg("Activate: read init response\n");
|
||||||
/* Should return 4-byte response */
|
aesX660_read_response(ssm, _dev, INIT_LEN, activate_read_init_cb);
|
||||||
aesX660_read_response(ssm, 4, activate_read_init_cb);
|
|
||||||
break;
|
break;
|
||||||
case ACTIVATE_SEND_CALIBRATE_CMD:
|
case ACTIVATE_SEND_CALIBRATE_CMD:
|
||||||
aesX660_send_cmd(ssm, calibrate_cmd, sizeof(calibrate_cmd),
|
aesX660_send_cmd(ssm, _dev, calibrate_cmd, sizeof(calibrate_cmd),
|
||||||
aesX660_send_cmd_cb);
|
aesX660_send_cmd_cb);
|
||||||
break;
|
break;
|
||||||
case ACTIVATE_READ_CALIBRATE_DATA:
|
case ACTIVATE_READ_CALIBRATE_DATA:
|
||||||
/* Should return 4-byte response */
|
aesX660_read_response(ssm, _dev, CALIBRATE_DATA_LEN, aesX660_read_calibrate_data_cb);
|
||||||
aesX660_read_response(ssm, 4, aesX660_read_calibrate_data_cb);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void activate_sm_complete(struct fpi_ssm *ssm)
|
static void activate_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = user_data;
|
||||||
int err = ssm->error;
|
int err = fpi_ssm_get_error(ssm);
|
||||||
fp_dbg("status %d", err);
|
fp_dbg("status %d", err);
|
||||||
fpi_imgdev_activate_complete(dev, err);
|
fpi_imgdev_activate_complete(dev, err);
|
||||||
fpi_ssm_free(ssm);
|
fpi_ssm_free(ssm);
|
||||||
@@ -600,18 +589,17 @@ static void activate_sm_complete(struct fpi_ssm *ssm)
|
|||||||
start_finger_detection(dev);
|
start_finger_detection(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
int aesX660_dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
int aesX660_dev_activate(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = fpi_ssm_new(dev->dev, activate_run_state,
|
fpi_ssm *ssm = fpi_ssm_new(FP_DEV(dev), activate_run_state,
|
||||||
ACTIVATE_NUM_STATES);
|
ACTIVATE_NUM_STATES, dev);
|
||||||
ssm->priv = dev;
|
|
||||||
fpi_ssm_start(ssm, activate_sm_complete);
|
fpi_ssm_start(ssm, activate_sm_complete);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void aesX660_dev_deactivate(struct fp_img_dev *dev)
|
void aesX660_dev_deactivate(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct aesX660_dev *aesdev = dev->priv;
|
struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
|
||||||
if (aesdev->fd_data_transfer)
|
if (aesdev->fd_data_transfer)
|
||||||
libusb_cancel_transfer(aesdev->fd_data_transfer);
|
libusb_cancel_transfer(aesdev->fd_data_transfer);
|
||||||
@@ -621,8 +609,8 @@ void aesX660_dev_deactivate(struct fp_img_dev *dev)
|
|||||||
|
|
||||||
static void complete_deactivation(struct fp_img_dev *dev)
|
static void complete_deactivation(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct aesX660_dev *aesdev = dev->priv;
|
struct aesX660_dev *aesdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
fp_dbg("");
|
G_DEBUG_HERE();
|
||||||
|
|
||||||
aesdev->deactivating = FALSE;
|
aesdev->deactivating = FALSE;
|
||||||
g_slist_free(aesdev->strips);
|
g_slist_free(aesdev->strips);
|
||||||
|
|||||||
@@ -41,6 +41,8 @@
|
|||||||
#define AESX660_IMAGE_OFFSET 43
|
#define AESX660_IMAGE_OFFSET 43
|
||||||
#define AESX660_BULK_TRANSFER_SIZE 4096
|
#define AESX660_BULK_TRANSFER_SIZE 4096
|
||||||
|
|
||||||
|
#define AESX660_FRAME_HEIGHT 8
|
||||||
|
|
||||||
struct aesX660_dev {
|
struct aesX660_dev {
|
||||||
GSList *strips;
|
GSList *strips;
|
||||||
size_t strips_len;
|
size_t strips_len;
|
||||||
@@ -55,12 +57,12 @@ struct aesX660_dev {
|
|||||||
size_t buffer_max;
|
size_t buffer_max;
|
||||||
|
|
||||||
/* Device-specific stuff */
|
/* Device-specific stuff */
|
||||||
int h_scale_factor;
|
|
||||||
struct aesX660_cmd *init_seqs[2];
|
struct aesX660_cmd *init_seqs[2];
|
||||||
size_t init_seqs_len[2];
|
size_t init_seqs_len[2];
|
||||||
unsigned char *start_imaging_cmd;
|
unsigned char *start_imaging_cmd;
|
||||||
size_t start_imaging_cmd_len;
|
size_t start_imaging_cmd_len;
|
||||||
unsigned int frame_width;
|
struct fpi_frame_asmbl_ctx *assembling_ctx;
|
||||||
|
uint16_t extra_img_flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct aesX660_cmd {
|
struct aesX660_cmd {
|
||||||
@@ -114,7 +116,7 @@ static const unsigned char calibrate_cmd[] = {
|
|||||||
0x06,
|
0x06,
|
||||||
};
|
};
|
||||||
|
|
||||||
int aesX660_dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state);
|
int aesX660_dev_activate(struct fp_img_dev *dev);
|
||||||
void aesX660_dev_deactivate(struct fp_img_dev *dev);
|
void aesX660_dev_deactivate(struct fp_img_dev *dev);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -27,19 +27,21 @@ enum {
|
|||||||
AES2501_ID = 4,
|
AES2501_ID = 4,
|
||||||
UPEKTC_ID = 5,
|
UPEKTC_ID = 5,
|
||||||
AES1610_ID = 6,
|
AES1610_ID = 6,
|
||||||
FDU2000_ID = 7,
|
/* FDU2000_ID = 7, */
|
||||||
VCOM5S_ID = 8,
|
VCOM5S_ID = 8,
|
||||||
UPEKSONLY_ID = 9,
|
UPEKSONLY_ID = 9,
|
||||||
VFS101_ID = 10,
|
VFS101_ID = 10,
|
||||||
VFS301_ID = 11,
|
VFS301_ID = 11,
|
||||||
AES2550_ID = 12,
|
AES2550_ID = 12,
|
||||||
UPEKE2_ID = 13,
|
/* UPEKE2_ID = 13 */
|
||||||
AES1660_ID = 14,
|
AES1660_ID = 14,
|
||||||
AES2660_ID = 15,
|
AES2660_ID = 15,
|
||||||
AES3500_ID = 16,
|
AES3500_ID = 16,
|
||||||
UPEKTC_IMG_ID = 17,
|
UPEKTC_IMG_ID = 17,
|
||||||
ETES603_ID = 18,
|
ETES603_ID = 18,
|
||||||
VFS5011_ID = 19,
|
VFS5011_ID = 19,
|
||||||
|
VFS0050_ID = 20,
|
||||||
|
ELAN_ID = 21,
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
988
libfprint/drivers/elan.c
Normal file
988
libfprint/drivers/elan.c
Normal file
@@ -0,0 +1,988 @@
|
|||||||
|
/*
|
||||||
|
* Elan driver for libfprint
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Igor Filatov <ia.filatov@gmail.com>
|
||||||
|
* Copyright (C) 2018 Sébastien Béchet <sebastien.bechet@osinix.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
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The algorithm which libfprint uses to match fingerprints doesn't like small
|
||||||
|
* images like the ones these drivers produce. There's just not enough minutiae
|
||||||
|
* (recognizable print-specific points) on them for a reliable match. This means
|
||||||
|
* that unless another matching algo is found/implemented, these readers will
|
||||||
|
* not work as good with libfprint as they do with vendor drivers.
|
||||||
|
*
|
||||||
|
* To get bigger images the driver expects you to swipe the finger over the
|
||||||
|
* reader. This works quite well for readers with a rectangular 144x64 sensor.
|
||||||
|
* Worse than real swipe readers but good enough for day-to-day use. It needs
|
||||||
|
* a steady and relatively slow swipe. There are also square 96x96 sensors and
|
||||||
|
* I don't know whether they are in fact usable or not because I don't have one.
|
||||||
|
* I imagine they'd be less reliable because the resulting image is even
|
||||||
|
* smaller. If they can't be made usable with libfprint, I might end up dropping
|
||||||
|
* them because it's better than saying they work when they don't.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define FP_COMPONENT "elan"
|
||||||
|
|
||||||
|
#include "drivers_api.h"
|
||||||
|
#include "elan.h"
|
||||||
|
|
||||||
|
#define dbg_buf(buf, len) \
|
||||||
|
if (len == 1) \
|
||||||
|
fp_dbg("%02x", buf[0]); \
|
||||||
|
else if (len == 2) \
|
||||||
|
fp_dbg("%04x", buf[0] << 8 | buf[1]); \
|
||||||
|
else if (len > 2) \
|
||||||
|
fp_dbg("%04x... (%d bytes)", buf[0] << 8 | buf[1], len)
|
||||||
|
|
||||||
|
unsigned char elan_get_pixel(struct fpi_frame_asmbl_ctx *ctx,
|
||||||
|
struct fpi_frame *frame, unsigned int x,
|
||||||
|
unsigned int y)
|
||||||
|
{
|
||||||
|
return frame->data[x + y * ctx->frame_width];
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct fpi_frame_asmbl_ctx assembling_ctx = {
|
||||||
|
.frame_width = 0,
|
||||||
|
.frame_height = 0,
|
||||||
|
.image_width = 0,
|
||||||
|
.get_pixel = elan_get_pixel,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct elan_dev {
|
||||||
|
/* device config */
|
||||||
|
unsigned short dev_type;
|
||||||
|
unsigned short fw_ver;
|
||||||
|
void (*process_frame) (unsigned short *raw_frame, GSList ** frames);
|
||||||
|
/* end device config */
|
||||||
|
|
||||||
|
/* commands */
|
||||||
|
const struct elan_cmd *cmd;
|
||||||
|
int cmd_timeout;
|
||||||
|
fpi_usb_transfer *cur_transfer;
|
||||||
|
/* end commands */
|
||||||
|
|
||||||
|
/* state */
|
||||||
|
enum fp_imgdev_state dev_state;
|
||||||
|
enum fp_imgdev_state dev_state_next;
|
||||||
|
unsigned char *last_read;
|
||||||
|
unsigned char calib_atts_left;
|
||||||
|
unsigned char calib_status;
|
||||||
|
unsigned short *background;
|
||||||
|
unsigned char frame_width;
|
||||||
|
unsigned char frame_height;
|
||||||
|
unsigned char raw_frame_height;
|
||||||
|
int num_frames;
|
||||||
|
GSList *frames;
|
||||||
|
/* end state */
|
||||||
|
};
|
||||||
|
|
||||||
|
int cmp_short(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
return (int)(*(short *)a - *(short *)b);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void elan_dev_reset(struct elan_dev *elandev)
|
||||||
|
{
|
||||||
|
G_DEBUG_HERE();
|
||||||
|
|
||||||
|
BUG_ON(elandev->cur_transfer);
|
||||||
|
|
||||||
|
elandev->cmd = NULL;
|
||||||
|
elandev->cmd_timeout = ELAN_CMD_TIMEOUT;
|
||||||
|
|
||||||
|
elandev->calib_status = 0;
|
||||||
|
|
||||||
|
g_free(elandev->last_read);
|
||||||
|
elandev->last_read = NULL;
|
||||||
|
|
||||||
|
g_slist_free_full(elandev->frames, g_free);
|
||||||
|
elandev->frames = NULL;
|
||||||
|
elandev->num_frames = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void elan_save_frame(struct elan_dev *elandev, unsigned short *frame)
|
||||||
|
{
|
||||||
|
G_DEBUG_HERE();
|
||||||
|
|
||||||
|
/* so far 3 types of readers by sensor dimensions and orientation have been
|
||||||
|
* seen in the wild:
|
||||||
|
* 1. 144x64. Raw images are in portrait orientation while readers themselves
|
||||||
|
* are placed (e.g. built into a touchpad) in landscape orientation. These
|
||||||
|
* need to be rotated before assembling.
|
||||||
|
* 2. 96x96 rotated. Like the first type but square. Likewise, need to be
|
||||||
|
* rotated before assembling.
|
||||||
|
* 3. 96x96 normal. Square and need NOT be rotated. So far there's only been
|
||||||
|
* 1 report of a 0c03 of this type. Hopefully this type can be identified
|
||||||
|
* by device id (and manufacturers don't just install the readers as they
|
||||||
|
* please).
|
||||||
|
* we also discard stripes of 'frame_margin' from bottom and top because
|
||||||
|
* assembling works bad for tall frames */
|
||||||
|
|
||||||
|
unsigned char frame_width = elandev->frame_width;
|
||||||
|
unsigned char frame_height = elandev->frame_height;
|
||||||
|
unsigned char raw_height = elandev->raw_frame_height;
|
||||||
|
unsigned char frame_margin = (raw_height - elandev->frame_height) / 2;
|
||||||
|
int frame_idx, raw_idx;
|
||||||
|
|
||||||
|
for (int y = 0; y < frame_height; y++)
|
||||||
|
for (int x = 0; x < frame_width; x++) {
|
||||||
|
if (elandev->dev_type & ELAN_NOT_ROTATED)
|
||||||
|
raw_idx = x + (y + frame_margin) * frame_width;
|
||||||
|
else
|
||||||
|
raw_idx = frame_margin + y + x * raw_height;
|
||||||
|
frame_idx = x + y * frame_width;
|
||||||
|
frame[frame_idx] =
|
||||||
|
((unsigned short *)elandev->last_read)[raw_idx];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void elan_save_background(struct elan_dev *elandev)
|
||||||
|
{
|
||||||
|
G_DEBUG_HERE();
|
||||||
|
|
||||||
|
g_free(elandev->background);
|
||||||
|
elandev->background =
|
||||||
|
g_malloc(elandev->frame_width * elandev->frame_height *
|
||||||
|
sizeof(short));
|
||||||
|
elan_save_frame(elandev, elandev->background);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* save a frame as part of the fingerprint image
|
||||||
|
* background needs to have been captured for this routine to work
|
||||||
|
* Elantech recommends 2-step non-linear normalization in order to reduce
|
||||||
|
* 2^14 ADC resolution to 2^8 image:
|
||||||
|
*
|
||||||
|
* 1. background is subtracted (done here)
|
||||||
|
*
|
||||||
|
* 2. pixels are grouped in 3 groups by intensity and each group is mapped
|
||||||
|
* separately onto the normalized frame (done in elan_process_frame_*)
|
||||||
|
* ==== 16383 ____> ======== 255
|
||||||
|
* /
|
||||||
|
* ----- lvl3 __/
|
||||||
|
* 35% pixels
|
||||||
|
*
|
||||||
|
* ----- lvl2 --------> ======== 156
|
||||||
|
*
|
||||||
|
* 30% pixels
|
||||||
|
* ----- lvl1 --------> ======== 99
|
||||||
|
*
|
||||||
|
* 35% pixels
|
||||||
|
* ----- lvl0 __
|
||||||
|
* \
|
||||||
|
* ======== 0 \____> ======== 0
|
||||||
|
*
|
||||||
|
* For some devices we don't do 2. but instead do a simple linear mapping
|
||||||
|
* because it seems to produce better results (or at least as good):
|
||||||
|
* ==== 16383 ___> ======== 255
|
||||||
|
* /
|
||||||
|
* ------ max __/
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* ------ min __
|
||||||
|
* \
|
||||||
|
* ======== 0 \___> ======== 0
|
||||||
|
*/
|
||||||
|
static int elan_save_img_frame(struct elan_dev *elandev)
|
||||||
|
{
|
||||||
|
G_DEBUG_HERE();
|
||||||
|
|
||||||
|
unsigned int frame_size = elandev->frame_width * elandev->frame_height;
|
||||||
|
unsigned short *frame = g_malloc(frame_size * sizeof(short));
|
||||||
|
elan_save_frame(elandev, frame);
|
||||||
|
unsigned int sum = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < frame_size; i++) {
|
||||||
|
if (elandev->background[i] > frame[i])
|
||||||
|
frame[i] = 0;
|
||||||
|
else
|
||||||
|
frame[i] -= elandev->background[i];
|
||||||
|
sum += frame[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sum == 0) {
|
||||||
|
fp_dbg
|
||||||
|
("frame darker than background; finger present during calibration?");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
elandev->frames = g_slist_prepend(elandev->frames, frame);
|
||||||
|
elandev->num_frames += 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void elan_process_frame_linear(unsigned short *raw_frame,
|
||||||
|
GSList ** frames)
|
||||||
|
{
|
||||||
|
unsigned int frame_size =
|
||||||
|
assembling_ctx.frame_width * assembling_ctx.frame_height;
|
||||||
|
struct fpi_frame *frame =
|
||||||
|
g_malloc(frame_size + sizeof(struct fpi_frame));
|
||||||
|
|
||||||
|
G_DEBUG_HERE();
|
||||||
|
|
||||||
|
unsigned short min = 0xffff, max = 0;
|
||||||
|
for (int i = 0; i < frame_size; i++) {
|
||||||
|
if (raw_frame[i] < min)
|
||||||
|
min = raw_frame[i];
|
||||||
|
if (raw_frame[i] > max)
|
||||||
|
max = raw_frame[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
g_assert(max != min);
|
||||||
|
|
||||||
|
unsigned short px;
|
||||||
|
for (int i = 0; i < frame_size; i++) {
|
||||||
|
px = raw_frame[i];
|
||||||
|
px = (px - min) * 0xff / (max - min);
|
||||||
|
frame->data[i] = (unsigned char)px;
|
||||||
|
}
|
||||||
|
|
||||||
|
*frames = g_slist_prepend(*frames, frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void elan_process_frame_thirds(unsigned short *raw_frame,
|
||||||
|
GSList ** frames)
|
||||||
|
{
|
||||||
|
G_DEBUG_HERE();
|
||||||
|
|
||||||
|
unsigned int frame_size =
|
||||||
|
assembling_ctx.frame_width * assembling_ctx.frame_height;
|
||||||
|
struct fpi_frame *frame =
|
||||||
|
g_malloc(frame_size + sizeof(struct fpi_frame));
|
||||||
|
|
||||||
|
unsigned short lvl0, lvl1, lvl2, lvl3;
|
||||||
|
unsigned short *sorted = g_malloc(frame_size * sizeof(short));
|
||||||
|
memcpy(sorted, raw_frame, frame_size * sizeof(short));
|
||||||
|
qsort(sorted, frame_size, sizeof(short), cmp_short);
|
||||||
|
lvl0 = sorted[0];
|
||||||
|
lvl1 = sorted[frame_size * 3 / 10];
|
||||||
|
lvl2 = sorted[frame_size * 65 / 100];
|
||||||
|
lvl3 = sorted[frame_size - 1];
|
||||||
|
g_free(sorted);
|
||||||
|
|
||||||
|
unsigned short px;
|
||||||
|
for (int i = 0; i < frame_size; i++) {
|
||||||
|
px = raw_frame[i];
|
||||||
|
if (lvl0 <= px && px < lvl1)
|
||||||
|
px = (px - lvl0) * 99 / (lvl1 - lvl0);
|
||||||
|
else if (lvl1 <= px && px < lvl2)
|
||||||
|
px = 99 + ((px - lvl1) * 56 / (lvl2 - lvl1));
|
||||||
|
else // (lvl2 <= px && px <= lvl3)
|
||||||
|
px = 155 + ((px - lvl2) * 100 / (lvl3 - lvl2));
|
||||||
|
frame->data[i] = (unsigned char)px;
|
||||||
|
}
|
||||||
|
|
||||||
|
*frames = g_slist_prepend(*frames, frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void elan_submit_image(struct fp_img_dev *dev)
|
||||||
|
{
|
||||||
|
struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
int num_frames;
|
||||||
|
GSList *raw_frames;
|
||||||
|
GSList *frames = NULL;
|
||||||
|
struct fp_img *img;
|
||||||
|
|
||||||
|
G_DEBUG_HERE();
|
||||||
|
|
||||||
|
num_frames = elandev->num_frames - ELAN_SKIP_LAST_FRAMES;
|
||||||
|
raw_frames = g_slist_nth(elandev->frames, ELAN_SKIP_LAST_FRAMES);
|
||||||
|
|
||||||
|
assembling_ctx.frame_width = elandev->frame_width;
|
||||||
|
assembling_ctx.frame_height = elandev->frame_height;
|
||||||
|
assembling_ctx.image_width = elandev->frame_width * 3 / 2;
|
||||||
|
g_slist_foreach(raw_frames, (GFunc) elandev->process_frame, &frames);
|
||||||
|
fpi_do_movement_estimation(&assembling_ctx, frames, num_frames);
|
||||||
|
img = fpi_assemble_frames(&assembling_ctx, frames, num_frames);
|
||||||
|
|
||||||
|
img->flags |= FP_IMG_PARTIAL;
|
||||||
|
fpi_imgdev_image_captured(dev, img);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void elan_cmd_done(fpi_ssm *ssm)
|
||||||
|
{
|
||||||
|
G_DEBUG_HERE();
|
||||||
|
fpi_ssm_next_state(ssm);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void elan_cmd_cb(struct libusb_transfer *transfer,
|
||||||
|
struct fp_dev *_dev,
|
||||||
|
fpi_ssm *ssm,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
struct fp_img_dev *dev;
|
||||||
|
struct elan_dev *elandev;
|
||||||
|
|
||||||
|
G_DEBUG_HERE();
|
||||||
|
|
||||||
|
if (transfer->status == LIBUSB_TRANSFER_CANCELLED) {
|
||||||
|
fp_dbg("transfer cancelled");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev = FP_IMG_DEV(_dev);
|
||||||
|
elandev = FP_INSTANCE_DATA(_dev);
|
||||||
|
elandev->cur_transfer = NULL;
|
||||||
|
|
||||||
|
switch (transfer->status) {
|
||||||
|
case LIBUSB_TRANSFER_COMPLETED:
|
||||||
|
if (transfer->length != transfer->actual_length) {
|
||||||
|
fp_dbg("transfer length error: expected %d, got %d",
|
||||||
|
transfer->length, transfer->actual_length);
|
||||||
|
elan_dev_reset(elandev);
|
||||||
|
fpi_ssm_mark_failed(ssm, -EPROTO);
|
||||||
|
} else if (transfer->endpoint & LIBUSB_ENDPOINT_IN) {
|
||||||
|
/* just finished receiving */
|
||||||
|
elandev->last_read = g_memdup(transfer->buffer, transfer->actual_length);
|
||||||
|
dbg_buf(transfer->buffer, transfer->actual_length);
|
||||||
|
elan_cmd_done(ssm);
|
||||||
|
} else {
|
||||||
|
/* just finished sending */
|
||||||
|
G_DEBUG_HERE();
|
||||||
|
elan_cmd_read(ssm, dev);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LIBUSB_TRANSFER_TIMED_OUT:
|
||||||
|
fp_dbg("transfer timed out");
|
||||||
|
fpi_ssm_mark_failed(ssm, -ETIMEDOUT);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fp_dbg("transfer failed: %d", transfer->status);
|
||||||
|
elan_dev_reset(elandev);
|
||||||
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void elan_cmd_read(fpi_ssm *ssm, struct fp_img_dev *dev)
|
||||||
|
{
|
||||||
|
struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
int response_len = elandev->cmd->response_len;
|
||||||
|
unsigned char *buffer;
|
||||||
|
|
||||||
|
G_DEBUG_HERE();
|
||||||
|
|
||||||
|
if (elandev->cmd->response_len == ELAN_CMD_SKIP_READ) {
|
||||||
|
fp_dbg("skipping read, not expecting anything");
|
||||||
|
elan_cmd_done(ssm);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (elandev->dev_type == ELAN_0C42) {
|
||||||
|
/* ELAN_0C42 sends an extra byte in one byte responses */
|
||||||
|
if (elandev->cmd->response_len == 1)
|
||||||
|
response_len = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (elandev->cmd->cmd == get_image_cmd.cmd)
|
||||||
|
/* raw data has 2-byte "pixels" and the frame is vertical */
|
||||||
|
response_len =
|
||||||
|
elandev->raw_frame_height * elandev->frame_width * 2;
|
||||||
|
|
||||||
|
g_clear_pointer(&elandev->last_read, g_free);
|
||||||
|
buffer = g_malloc(response_len);
|
||||||
|
|
||||||
|
elandev->cur_transfer = fpi_usb_fill_bulk_transfer(FP_DEV(dev),
|
||||||
|
ssm,
|
||||||
|
elandev->cmd->response_in,
|
||||||
|
buffer,
|
||||||
|
response_len,
|
||||||
|
elan_cmd_cb,
|
||||||
|
NULL,
|
||||||
|
elandev->cmd_timeout);
|
||||||
|
int r = fpi_usb_submit_transfer(elandev->cur_transfer);
|
||||||
|
if (r < 0)
|
||||||
|
fpi_ssm_mark_failed(ssm, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
elan_run_cmd(fpi_ssm *ssm,
|
||||||
|
struct fp_img_dev *dev,
|
||||||
|
const struct elan_cmd *cmd,
|
||||||
|
int cmd_timeout)
|
||||||
|
{
|
||||||
|
struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
|
||||||
|
dbg_buf(cmd->cmd, 2);
|
||||||
|
|
||||||
|
elandev->cmd = cmd;
|
||||||
|
if (cmd_timeout != -1)
|
||||||
|
elandev->cmd_timeout = cmd_timeout;
|
||||||
|
|
||||||
|
if (cmd->devices != ELAN_ALL_DEV && !(cmd->devices & elandev->dev_type)) {
|
||||||
|
fp_dbg("skipping command 0x%x 0x%x for this device (for devices 0x%x but device is 0x%x)",
|
||||||
|
cmd->cmd[0], cmd->cmd[1], cmd->devices, elandev->dev_type);
|
||||||
|
elan_cmd_done(ssm);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
elandev->cur_transfer = fpi_usb_fill_bulk_transfer(FP_DEV(dev),
|
||||||
|
ssm,
|
||||||
|
ELAN_EP_CMD_OUT,
|
||||||
|
g_memdup((char *) cmd->cmd, ELAN_CMD_LEN),
|
||||||
|
ELAN_CMD_LEN,
|
||||||
|
elan_cmd_cb,
|
||||||
|
NULL,
|
||||||
|
elandev->cmd_timeout);
|
||||||
|
int r = fpi_usb_submit_transfer(elandev->cur_transfer);
|
||||||
|
if (r < 0)
|
||||||
|
fpi_ssm_mark_failed(ssm, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum stop_capture_states {
|
||||||
|
STOP_CAPTURE,
|
||||||
|
STOP_CAPTURE_NUM_STATES,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void stop_capture_run_state(fpi_ssm *ssm, struct fp_dev *dev, void *user_data)
|
||||||
|
{
|
||||||
|
G_DEBUG_HERE();
|
||||||
|
|
||||||
|
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||||
|
case STOP_CAPTURE:
|
||||||
|
elan_run_cmd(ssm, FP_IMG_DEV(dev), &stop_cmd, ELAN_CMD_TIMEOUT);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stop_capture_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
|
{
|
||||||
|
struct fp_img_dev *dev = user_data;
|
||||||
|
struct elan_dev *elandev = FP_INSTANCE_DATA(_dev);
|
||||||
|
int error = fpi_ssm_get_error(ssm);
|
||||||
|
|
||||||
|
G_DEBUG_HERE();
|
||||||
|
|
||||||
|
fpi_ssm_free(ssm);
|
||||||
|
|
||||||
|
if (!error) {
|
||||||
|
fpi_imgdev_report_finger_status(dev, FALSE);
|
||||||
|
|
||||||
|
/* If verify or identify fails because of short swipe, we need to restart
|
||||||
|
* capture manually. It feels like libfprint or the application should know
|
||||||
|
* better if they want to retry, but they don't. Unless we've been asked to
|
||||||
|
* deactivate, try to re-enter the capture loop. Since state change is
|
||||||
|
* async, there's still a chance to be deactivated by another pending
|
||||||
|
* event. */
|
||||||
|
if (elandev->dev_state_next != IMGDEV_STATE_INACTIVE)
|
||||||
|
dev_change_state(dev, IMGDEV_STATE_AWAIT_FINGER_ON);
|
||||||
|
|
||||||
|
} else if (error != -ECANCELED)
|
||||||
|
fpi_imgdev_abort_scan(dev, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void elan_stop_capture(struct fp_img_dev *dev)
|
||||||
|
{
|
||||||
|
struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
|
||||||
|
G_DEBUG_HERE();
|
||||||
|
|
||||||
|
elan_dev_reset(elandev);
|
||||||
|
|
||||||
|
fpi_ssm *ssm =
|
||||||
|
fpi_ssm_new(FP_DEV(dev), stop_capture_run_state,
|
||||||
|
STOP_CAPTURE_NUM_STATES, dev);
|
||||||
|
fpi_ssm_start(ssm, stop_capture_complete);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum capture_states {
|
||||||
|
CAPTURE_LED_ON,
|
||||||
|
CAPTURE_WAIT_FINGER,
|
||||||
|
CAPTURE_READ_DATA,
|
||||||
|
CAPTURE_CHECK_ENOUGH_FRAMES,
|
||||||
|
CAPTURE_NUM_STATES,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void capture_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
|
{
|
||||||
|
struct fp_img_dev *dev = user_data;
|
||||||
|
struct elan_dev *elandev = FP_INSTANCE_DATA(_dev);
|
||||||
|
int r;
|
||||||
|
|
||||||
|
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||||
|
case CAPTURE_LED_ON:
|
||||||
|
elan_run_cmd(ssm, dev, &led_on_cmd, ELAN_CMD_TIMEOUT);
|
||||||
|
break;
|
||||||
|
case CAPTURE_WAIT_FINGER:
|
||||||
|
elan_run_cmd(ssm, dev, &pre_scan_cmd, -1);
|
||||||
|
break;
|
||||||
|
case CAPTURE_READ_DATA:
|
||||||
|
/* 0x55 - finger present
|
||||||
|
* 0xff - device not calibrated (probably) */
|
||||||
|
if (elandev->last_read && elandev->last_read[0] == 0x55) {
|
||||||
|
if (elandev->dev_state == IMGDEV_STATE_AWAIT_FINGER_ON)
|
||||||
|
fpi_imgdev_report_finger_status(dev, TRUE);
|
||||||
|
elan_run_cmd(ssm, dev, &get_image_cmd, ELAN_CMD_TIMEOUT);
|
||||||
|
} else
|
||||||
|
fpi_ssm_mark_failed(ssm, -EBADMSG);
|
||||||
|
break;
|
||||||
|
case CAPTURE_CHECK_ENOUGH_FRAMES:
|
||||||
|
r = elan_save_img_frame(elandev);
|
||||||
|
if (r < 0)
|
||||||
|
fpi_ssm_mark_failed(ssm, r);
|
||||||
|
else if (elandev->num_frames < ELAN_MAX_FRAMES) {
|
||||||
|
/* quickly stop if finger is removed */
|
||||||
|
elandev->cmd_timeout = ELAN_FINGER_TIMEOUT;
|
||||||
|
fpi_ssm_jump_to_state(ssm, CAPTURE_WAIT_FINGER);
|
||||||
|
} else {
|
||||||
|
fpi_ssm_next_state(ssm);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void capture_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
|
{
|
||||||
|
struct fp_img_dev *dev = user_data;
|
||||||
|
struct elan_dev *elandev = FP_INSTANCE_DATA(_dev);
|
||||||
|
|
||||||
|
G_DEBUG_HERE();
|
||||||
|
|
||||||
|
if (fpi_ssm_get_error(ssm) == -ECANCELED) {
|
||||||
|
fpi_ssm_free(ssm);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* either max frames captured or timed out waiting for the next frame */
|
||||||
|
if (!fpi_ssm_get_error(ssm)
|
||||||
|
|| (fpi_ssm_get_error(ssm) == -ETIMEDOUT
|
||||||
|
&& fpi_ssm_get_cur_state(ssm) == CAPTURE_WAIT_FINGER))
|
||||||
|
if (elandev->num_frames >= ELAN_MIN_FRAMES)
|
||||||
|
elan_submit_image(dev);
|
||||||
|
else {
|
||||||
|
fp_dbg("swipe too short: want >= %d frames, got %d",
|
||||||
|
ELAN_MIN_FRAMES, elandev->num_frames);
|
||||||
|
fpi_imgdev_abort_scan(dev, FP_VERIFY_RETRY_TOO_SHORT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* other error
|
||||||
|
* It says "...abort_scan" but reporting 1 during verification makes it
|
||||||
|
* successful! */
|
||||||
|
else
|
||||||
|
fpi_imgdev_abort_scan(dev, fpi_ssm_get_error(ssm));
|
||||||
|
|
||||||
|
fpi_ssm_free(ssm);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void elan_capture(struct fp_img_dev *dev)
|
||||||
|
{
|
||||||
|
struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
|
||||||
|
G_DEBUG_HERE();
|
||||||
|
|
||||||
|
elan_dev_reset(elandev);
|
||||||
|
fpi_ssm *ssm =
|
||||||
|
fpi_ssm_new(FP_DEV(dev), capture_run_state, CAPTURE_NUM_STATES, dev);
|
||||||
|
fpi_ssm_start(ssm, capture_complete);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* this function needs to have elandev->background and elandev->last_read to be
|
||||||
|
* the calibration mean */
|
||||||
|
static int elan_need_calibration(struct elan_dev *elandev)
|
||||||
|
{
|
||||||
|
G_DEBUG_HERE();
|
||||||
|
|
||||||
|
unsigned short calib_mean =
|
||||||
|
elandev->last_read[0] * 0xff + elandev->last_read[1];
|
||||||
|
unsigned int bg_mean = 0, delta;
|
||||||
|
unsigned int frame_size = elandev->frame_width * elandev->frame_height;
|
||||||
|
|
||||||
|
g_assert(frame_size != 0);
|
||||||
|
|
||||||
|
if (elandev->dev_type == ELAN_0C42) {
|
||||||
|
if (calib_mean > 5500 ||
|
||||||
|
calib_mean < 2500) {
|
||||||
|
fp_dbg("Forcing needed recalibration");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < frame_size; i++)
|
||||||
|
bg_mean += elandev->background[i];
|
||||||
|
bg_mean /= frame_size;
|
||||||
|
|
||||||
|
delta =
|
||||||
|
bg_mean > calib_mean ? bg_mean - calib_mean : calib_mean - bg_mean;
|
||||||
|
|
||||||
|
fp_dbg("calibration mean: %d, bg mean: %d, delta: %d", calib_mean,
|
||||||
|
bg_mean, delta);
|
||||||
|
|
||||||
|
return delta > ELAN_CALIBRATION_MAX_DELTA ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum calibrate_states {
|
||||||
|
CALIBRATE_GET_BACKGROUND,
|
||||||
|
CALIBRATE_SAVE_BACKGROUND,
|
||||||
|
CALIBRATE_GET_MEAN,
|
||||||
|
CALIBRATE_CHECK_NEEDED,
|
||||||
|
CALIBRATE_GET_STATUS,
|
||||||
|
CALIBRATE_CHECK_STATUS,
|
||||||
|
CALIBRATE_REPEAT_STATUS,
|
||||||
|
CALIBRATE_NUM_STATES,
|
||||||
|
};
|
||||||
|
|
||||||
|
static gboolean elan_supports_calibration(struct elan_dev *elandev)
|
||||||
|
{
|
||||||
|
if (elandev->dev_type == ELAN_0C42)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
return elandev->fw_ver >= ELAN_MIN_CALIBRATION_FW;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void calibrate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
|
{
|
||||||
|
struct fp_img_dev *dev = user_data;
|
||||||
|
struct elan_dev *elandev = FP_INSTANCE_DATA(_dev);
|
||||||
|
|
||||||
|
G_DEBUG_HERE();
|
||||||
|
|
||||||
|
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||||
|
case CALIBRATE_GET_BACKGROUND:
|
||||||
|
elan_run_cmd(ssm, dev, &get_image_cmd, ELAN_CMD_TIMEOUT);
|
||||||
|
break;
|
||||||
|
case CALIBRATE_SAVE_BACKGROUND:
|
||||||
|
elan_save_background(elandev);
|
||||||
|
if (!elan_supports_calibration(elandev)) {
|
||||||
|
fp_dbg("FW does not support calibration");
|
||||||
|
fpi_ssm_mark_completed(ssm);
|
||||||
|
} else
|
||||||
|
fpi_ssm_next_state(ssm);
|
||||||
|
break;
|
||||||
|
case CALIBRATE_GET_MEAN:
|
||||||
|
elan_run_cmd(ssm, dev, &get_calib_mean_cmd, ELAN_CMD_TIMEOUT);
|
||||||
|
break;
|
||||||
|
case CALIBRATE_CHECK_NEEDED:
|
||||||
|
if (elan_need_calibration(elandev)) {
|
||||||
|
elandev->calib_status = 0;
|
||||||
|
fpi_ssm_next_state(ssm);
|
||||||
|
} else
|
||||||
|
fpi_ssm_mark_completed(ssm);
|
||||||
|
break;
|
||||||
|
case CALIBRATE_GET_STATUS:
|
||||||
|
elandev->calib_atts_left -= 1;
|
||||||
|
if (elandev->calib_atts_left)
|
||||||
|
elan_run_cmd(ssm, dev, &get_calib_status_cmd,
|
||||||
|
ELAN_CMD_TIMEOUT);
|
||||||
|
else {
|
||||||
|
fp_dbg("calibration failed");
|
||||||
|
fpi_ssm_mark_failed(ssm, -1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CALIBRATE_CHECK_STATUS:
|
||||||
|
/* 0x01 - retry, 0x03 - ok
|
||||||
|
* It appears that when reading the response soon after 0x4023 the device
|
||||||
|
* can return 0x03, and only after some time (up to 100 ms) the response
|
||||||
|
* changes to 0x01. It stays that way for some time and then changes back
|
||||||
|
* to 0x03. Because of this we don't just expect 0x03, we want to see 0x01
|
||||||
|
* first. This is to make sure that a full calibration loop has completed */
|
||||||
|
fp_dbg("calibration status: 0x%02x", elandev->last_read[0]);
|
||||||
|
if (elandev->calib_status == 0x01
|
||||||
|
&& elandev->last_read[0] == 0x03) {
|
||||||
|
elandev->calib_status = 0x03;
|
||||||
|
fpi_ssm_jump_to_state(ssm, CALIBRATE_GET_BACKGROUND);
|
||||||
|
} else {
|
||||||
|
fpi_timeout *timeout;
|
||||||
|
|
||||||
|
if (elandev->calib_status == 0x00
|
||||||
|
&& elandev->last_read[0] == 0x01)
|
||||||
|
elandev->calib_status = 0x01;
|
||||||
|
timeout = fpi_timeout_add(50, fpi_ssm_next_state_timeout_cb, _dev, ssm);
|
||||||
|
fpi_timeout_set_name(timeout, "calibrate_run_state");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CALIBRATE_REPEAT_STATUS:
|
||||||
|
fpi_ssm_jump_to_state(ssm, CALIBRATE_GET_STATUS);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void calibrate_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
|
{
|
||||||
|
struct fp_img_dev *dev = user_data;
|
||||||
|
|
||||||
|
G_DEBUG_HERE();
|
||||||
|
|
||||||
|
|
||||||
|
if (fpi_ssm_get_error(ssm) != -ECANCELED)
|
||||||
|
elan_capture(dev);
|
||||||
|
|
||||||
|
fpi_ssm_free(ssm);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void elan_calibrate(struct fp_img_dev *dev)
|
||||||
|
{
|
||||||
|
struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
|
||||||
|
G_DEBUG_HERE();
|
||||||
|
|
||||||
|
elan_dev_reset(elandev);
|
||||||
|
elandev->calib_atts_left = ELAN_CALIBRATION_ATTEMPTS;
|
||||||
|
|
||||||
|
fpi_ssm *ssm = fpi_ssm_new(FP_DEV(dev), calibrate_run_state,
|
||||||
|
CALIBRATE_NUM_STATES, dev);
|
||||||
|
fpi_ssm_start(ssm, calibrate_complete);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum activate_states {
|
||||||
|
ACTIVATE_GET_FW_VER,
|
||||||
|
ACTIVATE_SET_FW_VER,
|
||||||
|
ACTIVATE_GET_SENSOR_DIM,
|
||||||
|
ACTIVATE_SET_SENSOR_DIM,
|
||||||
|
ACTIVATE_CMD_1,
|
||||||
|
ACTIVATE_NUM_STATES,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void activate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
|
{
|
||||||
|
struct fp_img_dev *dev = user_data;
|
||||||
|
struct elan_dev *elandev = FP_INSTANCE_DATA(_dev);
|
||||||
|
|
||||||
|
G_DEBUG_HERE();
|
||||||
|
|
||||||
|
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||||
|
case ACTIVATE_GET_FW_VER:
|
||||||
|
elan_run_cmd(ssm, dev, &get_fw_ver_cmd, ELAN_CMD_TIMEOUT);
|
||||||
|
break;
|
||||||
|
case ACTIVATE_SET_FW_VER:
|
||||||
|
elandev->fw_ver =
|
||||||
|
(elandev->last_read[0] << 8 | elandev->last_read[1]);
|
||||||
|
fp_dbg("FW ver 0x%04hx", elandev->fw_ver);
|
||||||
|
fpi_ssm_next_state(ssm);
|
||||||
|
break;
|
||||||
|
case ACTIVATE_GET_SENSOR_DIM:
|
||||||
|
elan_run_cmd(ssm, dev, &get_sensor_dim_cmd, ELAN_CMD_TIMEOUT);
|
||||||
|
break;
|
||||||
|
case ACTIVATE_SET_SENSOR_DIM:
|
||||||
|
/* see elan_save_frame for details */
|
||||||
|
if (elandev->dev_type & ELAN_NOT_ROTATED) {
|
||||||
|
elandev->frame_width = elandev->last_read[0];
|
||||||
|
elandev->frame_height = elandev->raw_frame_height =
|
||||||
|
elandev->last_read[2];
|
||||||
|
} else {
|
||||||
|
elandev->frame_width = elandev->last_read[2];
|
||||||
|
elandev->frame_height = elandev->raw_frame_height =
|
||||||
|
elandev->last_read[0];
|
||||||
|
}
|
||||||
|
/* Work-around sensors returning the sizes as zero-based index
|
||||||
|
* rather than the number of pixels. */
|
||||||
|
if ((elandev->frame_width % 2 == 1) &&
|
||||||
|
(elandev->frame_height % 2 == 1)) {
|
||||||
|
elandev->frame_width++;
|
||||||
|
elandev->frame_height++;
|
||||||
|
elandev->raw_frame_height = elandev->frame_height;
|
||||||
|
}
|
||||||
|
if (elandev->frame_height > ELAN_MAX_FRAME_HEIGHT)
|
||||||
|
elandev->frame_height = ELAN_MAX_FRAME_HEIGHT;
|
||||||
|
fp_dbg("sensor dimensions, WxH: %dx%d", elandev->frame_width,
|
||||||
|
elandev->raw_frame_height);
|
||||||
|
fpi_ssm_next_state(ssm);
|
||||||
|
break;
|
||||||
|
case ACTIVATE_CMD_1:
|
||||||
|
/* TODO: find out what this does, if we need it */
|
||||||
|
elan_run_cmd(ssm, dev, &activate_cmd_1, ELAN_CMD_TIMEOUT);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void activate_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
|
{
|
||||||
|
struct fp_img_dev *dev = user_data;
|
||||||
|
|
||||||
|
G_DEBUG_HERE();
|
||||||
|
|
||||||
|
if (fpi_ssm_get_error(ssm) != -ECANCELED) {
|
||||||
|
fpi_imgdev_activate_complete(dev, fpi_ssm_get_error(ssm));
|
||||||
|
}
|
||||||
|
|
||||||
|
fpi_ssm_free(ssm);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void elan_activate(struct fp_img_dev *dev)
|
||||||
|
{
|
||||||
|
struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
|
||||||
|
G_DEBUG_HERE();
|
||||||
|
elan_dev_reset(elandev);
|
||||||
|
|
||||||
|
fpi_ssm *ssm =
|
||||||
|
fpi_ssm_new(FP_DEV(dev), activate_run_state, ACTIVATE_NUM_STATES, dev);
|
||||||
|
fpi_ssm_start(ssm, activate_complete);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||||
|
{
|
||||||
|
struct elan_dev *elandev;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
G_DEBUG_HERE();
|
||||||
|
|
||||||
|
r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||||
|
if (r < 0) {
|
||||||
|
fp_err("could not claim interface 0: %s", libusb_error_name(r));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
elandev = g_malloc0(sizeof(struct elan_dev));
|
||||||
|
fp_dev_set_instance_data(FP_DEV(dev), elandev);
|
||||||
|
|
||||||
|
/* common params */
|
||||||
|
elandev->dev_type = driver_data;
|
||||||
|
elandev->background = NULL;
|
||||||
|
elandev->process_frame = elan_process_frame_thirds;
|
||||||
|
|
||||||
|
switch (driver_data) {
|
||||||
|
case ELAN_0907:
|
||||||
|
elandev->process_frame = elan_process_frame_linear;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fpi_imgdev_open_complete(dev, 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void elan_deactivate(struct fp_img_dev *dev)
|
||||||
|
{
|
||||||
|
G_DEBUG_HERE();
|
||||||
|
|
||||||
|
fpi_imgdev_deactivate_complete(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dev_deinit(struct fp_img_dev *dev)
|
||||||
|
{
|
||||||
|
struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
|
||||||
|
G_DEBUG_HERE();
|
||||||
|
|
||||||
|
elan_dev_reset(elandev);
|
||||||
|
g_free(elandev->background);
|
||||||
|
g_free(elandev);
|
||||||
|
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||||
|
fpi_imgdev_close_complete(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dev_activate(struct fp_img_dev *dev)
|
||||||
|
{
|
||||||
|
G_DEBUG_HERE();
|
||||||
|
elan_activate(dev);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void elan_change_state(struct fp_img_dev *dev)
|
||||||
|
{
|
||||||
|
struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
enum fp_imgdev_state next_state = elandev->dev_state_next;
|
||||||
|
|
||||||
|
if (elandev->dev_state == next_state) {
|
||||||
|
fp_dbg("already in %d", next_state);
|
||||||
|
return;
|
||||||
|
} else
|
||||||
|
fp_dbg("changing to %d", next_state);
|
||||||
|
|
||||||
|
switch (next_state) {
|
||||||
|
case IMGDEV_STATE_INACTIVE:
|
||||||
|
if (elandev->cur_transfer)
|
||||||
|
/* deactivation will complete in transfer callback */
|
||||||
|
fpi_usb_cancel_transfer(elandev->cur_transfer);
|
||||||
|
else
|
||||||
|
elan_deactivate(dev);
|
||||||
|
break;
|
||||||
|
case IMGDEV_STATE_AWAIT_FINGER_ON:
|
||||||
|
/* activation completed or another enroll stage started */
|
||||||
|
elan_calibrate(dev);
|
||||||
|
break;
|
||||||
|
case IMGDEV_STATE_CAPTURE:
|
||||||
|
/* not used */
|
||||||
|
break;
|
||||||
|
case IMGDEV_STATE_AWAIT_FINGER_OFF:
|
||||||
|
elan_stop_capture(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
elandev->dev_state = next_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
elan_change_state_async(struct fp_dev *dev,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
g_message ("state change dev: %p", dev);
|
||||||
|
elan_change_state(FP_IMG_DEV (dev));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dev_change_state(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
||||||
|
{
|
||||||
|
struct elan_dev *elandev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
fpi_timeout *timeout;
|
||||||
|
|
||||||
|
G_DEBUG_HERE();
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
case IMGDEV_STATE_INACTIVE:
|
||||||
|
case IMGDEV_STATE_AWAIT_FINGER_ON:
|
||||||
|
case IMGDEV_STATE_AWAIT_FINGER_OFF: {
|
||||||
|
char *name;
|
||||||
|
|
||||||
|
/* schedule state change instead of calling it directly to allow all actions
|
||||||
|
* related to the previous state to complete */
|
||||||
|
elandev->dev_state_next = state;
|
||||||
|
timeout = fpi_timeout_add(10, elan_change_state_async, FP_DEV(dev), NULL);
|
||||||
|
|
||||||
|
name = g_strdup_printf ("dev_change_state to %d", state);
|
||||||
|
fpi_timeout_set_name(timeout, name);
|
||||||
|
g_free (name);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case IMGDEV_STATE_CAPTURE:
|
||||||
|
/* TODO MAYBE: split capture ssm into smaller ssms and use this state */
|
||||||
|
elandev->dev_state = state;
|
||||||
|
elandev->dev_state_next = state;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fp_err("unrecognized state %d", state);
|
||||||
|
fpi_imgdev_session_error(dev, -EINVAL);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* as of time of writing libfprint never checks the return value */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dev_deactivate(struct fp_img_dev *dev)
|
||||||
|
{
|
||||||
|
G_DEBUG_HERE();
|
||||||
|
|
||||||
|
dev_change_state(dev, IMGDEV_STATE_INACTIVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct fp_img_driver elan_driver = {
|
||||||
|
.driver = {
|
||||||
|
.id = ELAN_ID,
|
||||||
|
.name = FP_COMPONENT,
|
||||||
|
.full_name = "ElanTech Fingerprint Sensor",
|
||||||
|
.id_table = elan_id_table,
|
||||||
|
.scan_type = FP_SCAN_TYPE_SWIPE,
|
||||||
|
},
|
||||||
|
.flags = 0,
|
||||||
|
|
||||||
|
.bz3_threshold = 24,
|
||||||
|
|
||||||
|
.open = dev_init,
|
||||||
|
.close = dev_deinit,
|
||||||
|
.activate = dev_activate,
|
||||||
|
.deactivate = dev_deactivate,
|
||||||
|
.change_state = dev_change_state,
|
||||||
|
};
|
||||||
224
libfprint/drivers/elan.h
Normal file
224
libfprint/drivers/elan.h
Normal file
@@ -0,0 +1,224 @@
|
|||||||
|
/*
|
||||||
|
* Elan driver for libfprint
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Igor Filatov <ia.filatov@gmail.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __ELAN_H
|
||||||
|
#define __ELAN_H
|
||||||
|
|
||||||
|
#include <libusb.h>
|
||||||
|
|
||||||
|
#define ELAN_VEND_ID 0x04f3
|
||||||
|
|
||||||
|
/* a default device type */
|
||||||
|
#define ELAN_ALL_DEV 0
|
||||||
|
|
||||||
|
/* devices with quirks */
|
||||||
|
#define ELAN_0907 (1 << 0)
|
||||||
|
#define ELAN_0C03 (1 << 1)
|
||||||
|
#define ELAN_0C42 (1 << 2)
|
||||||
|
|
||||||
|
/* devices which don't require frame rotation before assembling */
|
||||||
|
#define ELAN_NOT_ROTATED ELAN_0C03
|
||||||
|
|
||||||
|
/* min FW version that supports calibration */
|
||||||
|
#define ELAN_MIN_CALIBRATION_FW 0x0138
|
||||||
|
|
||||||
|
/* max difference between background image mean and calibration mean
|
||||||
|
* (the response value of get_calib_mean_cmd)*/
|
||||||
|
#define ELAN_CALIBRATION_MAX_DELTA 500
|
||||||
|
|
||||||
|
/* times to retry reading calibration status during one session
|
||||||
|
* generally prevents calibration from looping indefinitely */
|
||||||
|
#define ELAN_CALIBRATION_ATTEMPTS 10
|
||||||
|
|
||||||
|
/* min and max frames in a capture */
|
||||||
|
#define ELAN_MIN_FRAMES 7
|
||||||
|
#define ELAN_MAX_FRAMES 30
|
||||||
|
|
||||||
|
/* crop frames to this height to improve stitching */
|
||||||
|
#define ELAN_MAX_FRAME_HEIGHT 50
|
||||||
|
|
||||||
|
/* number of frames to drop at the end of capture because frames captured
|
||||||
|
* while the finger is being lifted can be bad */
|
||||||
|
#define ELAN_SKIP_LAST_FRAMES 2
|
||||||
|
|
||||||
|
#define ELAN_CMD_LEN 0x2
|
||||||
|
#define ELAN_EP_CMD_OUT (0x1 | LIBUSB_ENDPOINT_OUT)
|
||||||
|
#define ELAN_EP_CMD_IN (0x3 | LIBUSB_ENDPOINT_IN)
|
||||||
|
#define ELAN_EP_IMG_IN (0x2 | LIBUSB_ENDPOINT_IN)
|
||||||
|
|
||||||
|
/* used as response length to tell the driver to skip reading response */
|
||||||
|
#define ELAN_CMD_SKIP_READ 0
|
||||||
|
|
||||||
|
/* usual command timeout and timeout for when we need to check if the finger is
|
||||||
|
* still on the device */
|
||||||
|
#define ELAN_CMD_TIMEOUT 10000
|
||||||
|
#define ELAN_FINGER_TIMEOUT 200
|
||||||
|
|
||||||
|
struct elan_cmd {
|
||||||
|
unsigned char cmd[ELAN_CMD_LEN];
|
||||||
|
int response_len;
|
||||||
|
int response_in;
|
||||||
|
unsigned short devices;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct elan_cmd get_sensor_dim_cmd = {
|
||||||
|
.cmd = {0x00, 0x0c},
|
||||||
|
.response_len = 0x4,
|
||||||
|
.response_in = ELAN_EP_CMD_IN,
|
||||||
|
.devices = ELAN_ALL_DEV,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct elan_cmd get_fw_ver_cmd = {
|
||||||
|
.cmd = {0x40, 0x19},
|
||||||
|
.response_len = 0x2,
|
||||||
|
.response_in = ELAN_EP_CMD_IN,
|
||||||
|
.devices = ELAN_ALL_DEV,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* unknown, returns 0x0 0x1 on 0907 */
|
||||||
|
static const struct elan_cmd activate_cmd_1 = {
|
||||||
|
.cmd = {0x40, 0x2a},
|
||||||
|
.response_len = 0x2,
|
||||||
|
.response_in = ELAN_EP_CMD_IN,
|
||||||
|
.devices = ELAN_0907,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct elan_cmd get_image_cmd = {
|
||||||
|
.cmd = {0x00, 0x09},
|
||||||
|
/* raw frame sizes are calculated from image dimensions reported by the
|
||||||
|
* device */
|
||||||
|
.response_len = -1,
|
||||||
|
.response_in = ELAN_EP_IMG_IN,
|
||||||
|
.devices = ELAN_ALL_DEV,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct elan_cmd read_sensor_status_cmd = {
|
||||||
|
.cmd = {0x40, 0x13},
|
||||||
|
.response_len = 0x1,
|
||||||
|
.response_in = ELAN_EP_CMD_IN,
|
||||||
|
.devices = ELAN_ALL_DEV,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct elan_cmd get_calib_status_cmd = {
|
||||||
|
.cmd = {0x40, 0x23},
|
||||||
|
.response_len = 0x1,
|
||||||
|
.response_in = ELAN_EP_CMD_IN,
|
||||||
|
.devices = ELAN_ALL_DEV,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct elan_cmd get_calib_mean_cmd = {
|
||||||
|
.cmd = {0x40, 0x24},
|
||||||
|
.response_len = 0x2,
|
||||||
|
.response_in = ELAN_EP_CMD_IN,
|
||||||
|
.devices = ELAN_ALL_DEV,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct elan_cmd led_on_cmd = {
|
||||||
|
.cmd = {0x40, 0x31},
|
||||||
|
.response_len = ELAN_CMD_SKIP_READ,
|
||||||
|
.response_in = ELAN_EP_CMD_IN,
|
||||||
|
.devices = ELAN_ALL_DEV,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* wait for finger
|
||||||
|
* subsequent read will not complete until finger is placed on the reader */
|
||||||
|
static const struct elan_cmd pre_scan_cmd = {
|
||||||
|
.cmd = {0x40, 0x3f},
|
||||||
|
.response_len = 0x1,
|
||||||
|
.response_in = ELAN_EP_CMD_IN,
|
||||||
|
.devices = ELAN_ALL_DEV,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* led off, stop waiting for finger */
|
||||||
|
static const struct elan_cmd stop_cmd = {
|
||||||
|
.cmd = {0x00, 0x0b},
|
||||||
|
.response_len = ELAN_CMD_SKIP_READ,
|
||||||
|
.response_in = ELAN_EP_CMD_IN,
|
||||||
|
.devices = ELAN_ALL_DEV,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct usb_id elan_id_table[] = {
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0903,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0907,.driver_data = ELAN_0907},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c01,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c02,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c03,.driver_data = ELAN_0C03},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c04,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c05,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c06,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c07,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c08,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c09,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c0a,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c0b,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c0c,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c0d,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c0e,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c0f,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c10,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c11,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c12,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c13,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c14,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c15,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c16,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c17,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c18,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c19,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c1a,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c1b,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c1c,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c1d,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c1e,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c1f,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c20,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c21,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c22,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c23,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c24,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c25,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c26,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c27,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c28,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c29,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c2a,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c2b,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c2c,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c2d,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c2e,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c2f,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c30,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c31,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c32,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c33,.driver_data = ELAN_ALL_DEV},
|
||||||
|
{.vendor = ELAN_VEND_ID,.product = 0x0c42,.driver_data = ELAN_0C42},
|
||||||
|
{0, 0, 0,},
|
||||||
|
};
|
||||||
|
|
||||||
|
static void elan_cmd_done(fpi_ssm *ssm);
|
||||||
|
static void elan_cmd_read(fpi_ssm *ssm, struct fp_img_dev *dev);
|
||||||
|
|
||||||
|
static void elan_calibrate(struct fp_img_dev *dev);
|
||||||
|
static void elan_capture(struct fp_img_dev *dev);
|
||||||
|
static void elan_deactivate(struct fp_img_dev *dev);
|
||||||
|
|
||||||
|
static int dev_change_state(struct fp_img_dev *dev, enum fp_imgdev_state state);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -33,16 +33,9 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include <libusb.h>
|
|
||||||
#include <glib.h>
|
|
||||||
|
|
||||||
#define FP_COMPONENT "etes603"
|
#define FP_COMPONENT "etes603"
|
||||||
#include <fp_internal.h>
|
|
||||||
|
#include "drivers_api.h"
|
||||||
#include "driver_ids.h"
|
#include "driver_ids.h"
|
||||||
|
|
||||||
/* libusb defines */
|
/* libusb defines */
|
||||||
@@ -299,7 +292,7 @@ static void msg_get_regs(struct etes603_dev *dev, int n_args, ... )
|
|||||||
va_list ap;
|
va_list ap;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
assert(n_args > 0 && n_args <= REG_MAX);
|
g_assert(n_args > 0 && n_args <= REG_MAX);
|
||||||
|
|
||||||
msg_header_prepare(msg);
|
msg_header_prepare(msg);
|
||||||
msg->cmd = CMD_READ_REG;
|
msg->cmd = CMD_READ_REG;
|
||||||
@@ -348,7 +341,7 @@ static void msg_set_regs(struct etes603_dev *dev, int n_args, ...)
|
|||||||
va_list ap;
|
va_list ap;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
assert(n_args != 0 && n_args % 2 == 0 && n_args <= REG_MAX * 2);
|
g_assert(n_args != 0 && n_args % 2 == 0 && n_args <= REG_MAX * 2);
|
||||||
|
|
||||||
msg_header_prepare(msg);
|
msg_header_prepare(msg);
|
||||||
msg->cmd = CMD_WRITE_REG;
|
msg->cmd = CMD_WRITE_REG;
|
||||||
@@ -646,14 +639,11 @@ enum {
|
|||||||
static int async_tx(struct fp_img_dev *idev, unsigned int ep, void *cb,
|
static int async_tx(struct fp_img_dev *idev, unsigned int ep, void *cb,
|
||||||
void *cb_arg)
|
void *cb_arg)
|
||||||
{
|
{
|
||||||
struct etes603_dev *dev = idev->priv;
|
struct etes603_dev *dev = FP_INSTANCE_DATA(FP_DEV(idev));
|
||||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||||
unsigned char *buffer;
|
unsigned char *buffer;
|
||||||
int length;
|
int length;
|
||||||
|
|
||||||
if (!transfer)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
if (ep == EP_OUT) {
|
if (ep == EP_OUT) {
|
||||||
buffer = (unsigned char *)dev->req;
|
buffer = (unsigned char *)dev->req;
|
||||||
length = dev->req_len;
|
length = dev->req_len;
|
||||||
@@ -663,7 +653,7 @@ static int async_tx(struct fp_img_dev *idev, unsigned int ep, void *cb,
|
|||||||
} else {
|
} else {
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
libusb_fill_bulk_transfer(transfer, idev->udev, ep, buffer, length,
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(idev)), ep, buffer, length,
|
||||||
cb, cb_arg, BULK_TIMEOUT);
|
cb, cb_arg, BULK_TIMEOUT);
|
||||||
|
|
||||||
if (libusb_submit_transfer(transfer)) {
|
if (libusb_submit_transfer(transfer)) {
|
||||||
@@ -676,14 +666,14 @@ static int async_tx(struct fp_img_dev *idev, unsigned int ep, void *cb,
|
|||||||
|
|
||||||
static void async_tx_cb(struct libusb_transfer *transfer)
|
static void async_tx_cb(struct libusb_transfer *transfer)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
struct fp_img_dev *idev = ssm->priv;
|
struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm);
|
||||||
struct etes603_dev *dev = idev->priv;
|
struct etes603_dev *dev = FP_INSTANCE_DATA(FP_DEV(idev));
|
||||||
|
|
||||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||||
fp_warn("transfer is not completed (status=%d)",
|
fp_warn("transfer is not completed (status=%d)",
|
||||||
transfer->status);
|
transfer->status);
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
} else {
|
} else {
|
||||||
unsigned char endpoint = transfer->endpoint;
|
unsigned char endpoint = transfer->endpoint;
|
||||||
@@ -698,7 +688,7 @@ static void async_tx_cb(struct libusb_transfer *transfer)
|
|||||||
length, actual_length);
|
length, actual_length);
|
||||||
/* Chained with the answer */
|
/* Chained with the answer */
|
||||||
if (async_tx(idev, EP_IN, async_tx_cb, ssm))
|
if (async_tx(idev, EP_IN, async_tx_cb, ssm))
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
} else if (endpoint == EP_IN) {
|
} else if (endpoint == EP_IN) {
|
||||||
dev->ans_len = actual_length;
|
dev->ans_len = actual_length;
|
||||||
fpi_ssm_next_state(ssm);
|
fpi_ssm_next_state(ssm);
|
||||||
@@ -706,12 +696,12 @@ static void async_tx_cb(struct libusb_transfer *transfer)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void m_exit_state(struct fpi_ssm *ssm)
|
static void m_exit_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *idev = ssm->priv;
|
struct fp_img_dev *idev = user_data;
|
||||||
struct etes603_dev *dev = idev->priv;
|
struct etes603_dev *dev = FP_INSTANCE_DATA(_dev);
|
||||||
|
|
||||||
switch (ssm->cur_state) {
|
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||||
case EXIT_SET_REGS_REQ:
|
case EXIT_SET_REGS_REQ:
|
||||||
msg_set_regs(dev, 4, REG_VCO_CONTROL, REG_VCO_IDLE,
|
msg_set_regs(dev, 4, REG_VCO_CONTROL, REG_VCO_IDLE,
|
||||||
REG_MODE_CONTROL, REG_MODE_SLEEP);
|
REG_MODE_CONTROL, REG_MODE_SLEEP);
|
||||||
@@ -724,21 +714,21 @@ static void m_exit_state(struct fpi_ssm *ssm)
|
|||||||
fpi_ssm_mark_completed(ssm);
|
fpi_ssm_mark_completed(ssm);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fp_err("Unknown state %d", ssm->cur_state);
|
fp_err("Unknown state %d", fpi_ssm_get_cur_state(ssm));
|
||||||
goto err;
|
goto err;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
err:
|
err:
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void m_exit_complete(struct fpi_ssm *ssm)
|
static void m_exit_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *idev = ssm->priv;
|
struct fp_img_dev *idev = user_data;
|
||||||
|
|
||||||
if (ssm->error) {
|
if (fpi_ssm_get_error(ssm)) {
|
||||||
fp_err("Error switching the device to idle state");
|
fp_err("Error switching the device to idle state");
|
||||||
} else {
|
} else {
|
||||||
fp_dbg("The device is now in idle state");
|
fp_dbg("The device is now in idle state");
|
||||||
@@ -749,24 +739,23 @@ static void m_exit_complete(struct fpi_ssm *ssm)
|
|||||||
|
|
||||||
static void m_exit_start(struct fp_img_dev *idev)
|
static void m_exit_start(struct fp_img_dev *idev)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = fpi_ssm_new(idev->dev, m_exit_state,
|
fpi_ssm *ssm = fpi_ssm_new(FP_DEV(idev), m_exit_state,
|
||||||
EXIT_NUM_STATES);
|
EXIT_NUM_STATES, idev);
|
||||||
fp_dbg("Switching device to idle mode");
|
fp_dbg("Switching device to idle mode");
|
||||||
ssm->priv = idev;
|
|
||||||
fpi_ssm_start(ssm, m_exit_complete);
|
fpi_ssm_start(ssm, m_exit_complete);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void m_capture_state(struct fpi_ssm *ssm)
|
static void m_capture_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *idev = ssm->priv;
|
struct fp_img_dev *idev = user_data;
|
||||||
struct etes603_dev *dev = idev->priv;
|
struct etes603_dev *dev = FP_INSTANCE_DATA(_dev);
|
||||||
|
|
||||||
if (dev->is_active == FALSE) {
|
if (dev->is_active == FALSE) {
|
||||||
fpi_ssm_mark_completed(ssm);
|
fpi_ssm_mark_completed(ssm);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (ssm->cur_state) {
|
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||||
case CAP_FP_INIT_SET_REG10_REQ:
|
case CAP_FP_INIT_SET_REG10_REQ:
|
||||||
/* Reset fingerprint */
|
/* Reset fingerprint */
|
||||||
fp_dbg("Capturing a fingerprint...");
|
fp_dbg("Capturing a fingerprint...");
|
||||||
@@ -827,26 +816,26 @@ static void m_capture_state(struct fpi_ssm *ssm)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fp_err("Unknown state %d", ssm->cur_state);
|
fp_err("Unknown state %d", fpi_ssm_get_cur_state(ssm));
|
||||||
goto err;
|
goto err;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
err:
|
err:
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void m_capture_complete(struct fpi_ssm *ssm)
|
static void m_capture_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *idev = ssm->priv;
|
struct fp_img_dev *idev = user_data;
|
||||||
struct etes603_dev *dev = idev->priv;
|
struct etes603_dev *dev = FP_INSTANCE_DATA(_dev);
|
||||||
|
|
||||||
if (ssm->error) {
|
if (fpi_ssm_get_error(ssm)) {
|
||||||
if (idev->action_state != IMG_ACQUIRE_STATE_DEACTIVATING) {
|
if (fpi_imgdev_get_action_state(idev) != IMG_ACQUIRE_STATE_DEACTIVATING) {
|
||||||
fp_err("Error while capturing fingerprint "
|
fp_err("Error while capturing fingerprint "
|
||||||
"(ssm->error=%d)", ssm->error);
|
"(fpi_ssm_get_error(ssm)=%d)", fpi_ssm_get_error(ssm));
|
||||||
fpi_imgdev_session_error(idev, ssm->error);
|
fpi_imgdev_session_error(idev, fpi_ssm_get_error(ssm));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fpi_ssm_free(ssm);
|
fpi_ssm_free(ssm);
|
||||||
@@ -859,17 +848,17 @@ static void m_capture_complete(struct fpi_ssm *ssm)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void m_finger_state(struct fpi_ssm *ssm)
|
static void m_finger_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *idev = ssm->priv;
|
struct fp_img_dev *idev = user_data;
|
||||||
struct etes603_dev *dev = idev->priv;
|
struct etes603_dev *dev = FP_INSTANCE_DATA(_dev);
|
||||||
|
|
||||||
if (dev->is_active == FALSE) {
|
if (dev->is_active == FALSE) {
|
||||||
fpi_ssm_mark_completed(ssm);
|
fpi_ssm_mark_completed(ssm);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (ssm->cur_state) {
|
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||||
case FGR_FPA_INIT_SET_MODE_SLEEP_REQ:
|
case FGR_FPA_INIT_SET_MODE_SLEEP_REQ:
|
||||||
msg_set_mode_control(dev, REG_MODE_SLEEP);
|
msg_set_mode_control(dev, REG_MODE_SLEEP);
|
||||||
if (async_tx(idev, EP_OUT, async_tx_cb, ssm))
|
if (async_tx(idev, EP_OUT, async_tx_cb, ssm))
|
||||||
@@ -945,31 +934,30 @@ static void m_finger_state(struct fpi_ssm *ssm)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fp_err("Unknown state %d", ssm->cur_state);
|
fp_err("Unknown state %d", fpi_ssm_get_cur_state(ssm));
|
||||||
goto err;
|
goto err;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
err:
|
err:
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void m_finger_complete(struct fpi_ssm *ssm)
|
static void m_finger_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *idev = ssm->priv;
|
struct fp_img_dev *idev = user_data;
|
||||||
struct etes603_dev *dev = idev->priv;
|
struct etes603_dev *dev = FP_INSTANCE_DATA(_dev);
|
||||||
|
|
||||||
if (!ssm->error) {
|
if (!fpi_ssm_get_error(ssm)) {
|
||||||
struct fpi_ssm *ssm_cap;
|
fpi_ssm *ssm_cap;
|
||||||
ssm_cap = fpi_ssm_new(idev->dev, m_capture_state,
|
ssm_cap = fpi_ssm_new(FP_DEV(idev), m_capture_state,
|
||||||
CAP_NUM_STATES);
|
CAP_NUM_STATES, idev);
|
||||||
ssm_cap->priv = idev;
|
|
||||||
fpi_ssm_start(ssm_cap, m_capture_complete);
|
fpi_ssm_start(ssm_cap, m_capture_complete);
|
||||||
} else {
|
} else {
|
||||||
if (idev->action_state != IMG_ACQUIRE_STATE_DEACTIVATING) {
|
if (fpi_imgdev_get_action_state(idev) != IMG_ACQUIRE_STATE_DEACTIVATING) {
|
||||||
fp_err("Error while capturing fingerprint "
|
fp_err("Error while capturing fingerprint "
|
||||||
"(ssm->error=%d)", ssm->error);
|
"(fpi_ssm_get_error(ssm)=%d)", fpi_ssm_get_error(ssm));
|
||||||
fpi_imgdev_session_error(idev, -4);
|
fpi_imgdev_session_error(idev, -4);
|
||||||
}
|
}
|
||||||
dev->is_active = FALSE;
|
dev->is_active = FALSE;
|
||||||
@@ -980,19 +968,18 @@ static void m_finger_complete(struct fpi_ssm *ssm)
|
|||||||
|
|
||||||
static void m_start_fingerdetect(struct fp_img_dev *idev)
|
static void m_start_fingerdetect(struct fp_img_dev *idev)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssmf;
|
fpi_ssm *ssmf;
|
||||||
ssmf = fpi_ssm_new(idev->dev, m_finger_state, FGR_NUM_STATES);
|
ssmf = fpi_ssm_new(FP_DEV(idev), m_finger_state, FGR_NUM_STATES, idev);
|
||||||
ssmf->priv = idev;
|
|
||||||
fpi_ssm_start(ssmf, m_finger_complete);
|
fpi_ssm_start(ssmf, m_finger_complete);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Tune value of VRT and VRB for contrast and brightness.
|
* Tune value of VRT and VRB for contrast and brightness.
|
||||||
*/
|
*/
|
||||||
static void m_tunevrb_state(struct fpi_ssm *ssm)
|
static void m_tunevrb_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *idev = ssm->priv;
|
struct fp_img_dev *idev = user_data;
|
||||||
struct etes603_dev *dev = idev->priv;
|
struct etes603_dev *dev = FP_INSTANCE_DATA(_dev);
|
||||||
float hist[5];
|
float hist[5];
|
||||||
|
|
||||||
if (dev->is_active == FALSE) {
|
if (dev->is_active == FALSE) {
|
||||||
@@ -1000,10 +987,10 @@ static void m_tunevrb_state(struct fpi_ssm *ssm)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (ssm->cur_state) {
|
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||||
case TUNEVRB_INIT:
|
case TUNEVRB_INIT:
|
||||||
fp_dbg("Tuning of VRT/VRB");
|
fp_dbg("Tuning of VRT/VRB");
|
||||||
assert(dev->dcoffset);
|
g_assert(dev->dcoffset);
|
||||||
/* VRT(reg E1)=0x0A and VRB(reg E2)=0x10 are starting values */
|
/* VRT(reg E1)=0x0A and VRB(reg E2)=0x10 are starting values */
|
||||||
dev->vrt = 0x0A;
|
dev->vrt = 0x0A;
|
||||||
dev->vrb = 0x10;
|
dev->vrb = 0x10;
|
||||||
@@ -1131,26 +1118,26 @@ static void m_tunevrb_state(struct fpi_ssm *ssm)
|
|||||||
fpi_ssm_mark_completed(ssm);
|
fpi_ssm_mark_completed(ssm);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fp_err("Unknown state %d", ssm->cur_state);
|
fp_err("Unknown state %d", fpi_ssm_get_cur_state(ssm));
|
||||||
goto err;
|
goto err;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
err:
|
err:
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void m_tunevrb_complete(struct fpi_ssm *ssm)
|
static void m_tunevrb_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *idev = ssm->priv;
|
struct fp_img_dev *idev = user_data;
|
||||||
|
|
||||||
fpi_imgdev_activate_complete(idev, ssm->error != 0);
|
fpi_imgdev_activate_complete(idev, fpi_ssm_get_error(ssm) != 0);
|
||||||
if (!ssm->error) {
|
if (!fpi_ssm_get_error(ssm)) {
|
||||||
fp_dbg("Tuning is done. Starting finger detection.");
|
fp_dbg("Tuning is done. Starting finger detection.");
|
||||||
m_start_fingerdetect(idev);
|
m_start_fingerdetect(idev);
|
||||||
} else {
|
} else {
|
||||||
struct etes603_dev *dev = idev->priv;
|
struct etes603_dev *dev = FP_INSTANCE_DATA(_dev);
|
||||||
fp_err("Error while tuning VRT");
|
fp_err("Error while tuning VRT");
|
||||||
dev->is_active = FALSE;
|
dev->is_active = FALSE;
|
||||||
reset_param(dev);
|
reset_param(dev);
|
||||||
@@ -1163,10 +1150,10 @@ static void m_tunevrb_complete(struct fpi_ssm *ssm)
|
|||||||
* This function tunes the DCoffset value and adjusts the gain value if
|
* This function tunes the DCoffset value and adjusts the gain value if
|
||||||
* required.
|
* required.
|
||||||
*/
|
*/
|
||||||
static void m_tunedc_state(struct fpi_ssm *ssm)
|
static void m_tunedc_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *idev = ssm->priv;
|
struct fp_img_dev *idev = user_data;
|
||||||
struct etes603_dev *dev = idev->priv;
|
struct etes603_dev *dev = FP_INSTANCE_DATA(_dev);
|
||||||
|
|
||||||
if (dev->is_active == FALSE) {
|
if (dev->is_active == FALSE) {
|
||||||
fpi_ssm_mark_completed(ssm);
|
fpi_ssm_mark_completed(ssm);
|
||||||
@@ -1177,7 +1164,7 @@ static void m_tunedc_state(struct fpi_ssm *ssm)
|
|||||||
* captured traffic to make sure that the value is correct. */
|
* captured traffic to make sure that the value is correct. */
|
||||||
/* The default gain should work but it may reach a DCOffset limit so in
|
/* The default gain should work but it may reach a DCOffset limit so in
|
||||||
* this case we decrease the gain. */
|
* this case we decrease the gain. */
|
||||||
switch (ssm->cur_state) {
|
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||||
case TUNEDC_INIT:
|
case TUNEDC_INIT:
|
||||||
/* reg_e0 = 0x23 is sensor normal/small gain */
|
/* reg_e0 = 0x23 is sensor normal/small gain */
|
||||||
dev->gain = GAIN_SMALL_INIT;
|
dev->gain = GAIN_SMALL_INIT;
|
||||||
@@ -1255,28 +1242,27 @@ static void m_tunedc_state(struct fpi_ssm *ssm)
|
|||||||
fpi_ssm_mark_completed(ssm);
|
fpi_ssm_mark_completed(ssm);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fp_err("Unknown state %d", ssm->cur_state);
|
fp_err("Unknown state %d", fpi_ssm_get_cur_state(ssm));
|
||||||
goto err;
|
goto err;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
err:
|
err:
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void m_tunedc_complete(struct fpi_ssm *ssm)
|
static void m_tunedc_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *idev = ssm->priv;
|
struct fp_img_dev *idev = user_data;
|
||||||
if (!ssm->error) {
|
if (!fpi_ssm_get_error(ssm)) {
|
||||||
struct fpi_ssm *ssm_tune;
|
fpi_ssm *ssm_tune;
|
||||||
ssm_tune = fpi_ssm_new(idev->dev, m_tunevrb_state,
|
ssm_tune = fpi_ssm_new(FP_DEV(idev), m_tunevrb_state,
|
||||||
TUNEVRB_NUM_STATES);
|
TUNEVRB_NUM_STATES, idev);
|
||||||
ssm_tune->priv = idev;
|
|
||||||
fpi_ssm_start(ssm_tune, m_tunevrb_complete);
|
fpi_ssm_start(ssm_tune, m_tunevrb_complete);
|
||||||
} else {
|
} else {
|
||||||
struct etes603_dev *dev = idev->priv;
|
struct etes603_dev *dev = FP_INSTANCE_DATA(_dev);
|
||||||
fp_err("Error while tuning DCOFFSET");
|
fp_err("Error while tuning DCOFFSET");
|
||||||
dev->is_active = FALSE;
|
dev->is_active = FALSE;
|
||||||
reset_param(dev);
|
reset_param(dev);
|
||||||
@@ -1285,17 +1271,17 @@ static void m_tunedc_complete(struct fpi_ssm *ssm)
|
|||||||
fpi_ssm_free(ssm);
|
fpi_ssm_free(ssm);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void m_init_state(struct fpi_ssm *ssm)
|
static void m_init_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *idev = ssm->priv;
|
struct fp_img_dev *idev = user_data;
|
||||||
struct etes603_dev *dev = idev->priv;
|
struct etes603_dev *dev = FP_INSTANCE_DATA(_dev);
|
||||||
|
|
||||||
if (dev->is_active == FALSE) {
|
if (dev->is_active == FALSE) {
|
||||||
fpi_ssm_mark_completed(ssm);
|
fpi_ssm_mark_completed(ssm);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (ssm->cur_state) {
|
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||||
case INIT_CHECK_INFO_REQ:
|
case INIT_CHECK_INFO_REQ:
|
||||||
msg_get_regs(dev, 4, REG_INFO0, REG_INFO1, REG_INFO2,
|
msg_get_regs(dev, 4, REG_INFO0, REG_INFO1, REG_INFO2,
|
||||||
REG_INFO3);
|
REG_INFO3);
|
||||||
@@ -1330,7 +1316,7 @@ static void m_init_state(struct fpi_ssm *ssm)
|
|||||||
fpi_ssm_next_state(ssm);
|
fpi_ssm_next_state(ssm);
|
||||||
break;
|
break;
|
||||||
case INIT_SENSOR_REQ:
|
case INIT_SENSOR_REQ:
|
||||||
/* In captured traffic, those are splitted. */
|
/* In captured traffic, those are split. */
|
||||||
msg_set_regs(dev, 18, REG_MODE_CONTROL, REG_MODE_SLEEP,
|
msg_set_regs(dev, 18, REG_MODE_CONTROL, REG_MODE_SLEEP,
|
||||||
REG_50, 0x0F, REG_GAIN, 0x04, REG_VRT, 0x08,
|
REG_50, 0x0F, REG_GAIN, 0x04, REG_VRT, 0x08,
|
||||||
REG_VRB, 0x0D, REG_VCO_CONTROL, REG_VCO_RT,
|
REG_VRB, 0x0D, REG_VCO_CONTROL, REG_VCO_RT,
|
||||||
@@ -1375,28 +1361,27 @@ static void m_init_state(struct fpi_ssm *ssm)
|
|||||||
fpi_ssm_mark_completed(ssm);
|
fpi_ssm_mark_completed(ssm);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fp_err("Unknown state %d", ssm->cur_state);
|
fp_err("Unknown state %d", fpi_ssm_get_cur_state(ssm));
|
||||||
goto err;
|
goto err;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
err:
|
err:
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void m_init_complete(struct fpi_ssm *ssm)
|
static void m_init_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *idev = ssm->priv;
|
struct fp_img_dev *idev = user_data;
|
||||||
if (!ssm->error) {
|
if (!fpi_ssm_get_error(ssm)) {
|
||||||
struct fpi_ssm *ssm_tune;
|
fpi_ssm *ssm_tune;
|
||||||
ssm_tune = fpi_ssm_new(idev->dev, m_tunedc_state,
|
ssm_tune = fpi_ssm_new(FP_DEV(idev), m_tunedc_state,
|
||||||
TUNEDC_NUM_STATES);
|
TUNEDC_NUM_STATES, idev);
|
||||||
ssm_tune->priv = idev;
|
|
||||||
fpi_ssm_start(ssm_tune, m_tunedc_complete);
|
fpi_ssm_start(ssm_tune, m_tunedc_complete);
|
||||||
} else {
|
} else {
|
||||||
struct etes603_dev *dev = idev->priv;
|
struct etes603_dev *dev = FP_INSTANCE_DATA(_dev);
|
||||||
fp_err("Error initializing the device");
|
fp_err("Error initializing the device");
|
||||||
dev->is_active = FALSE;
|
dev->is_active = FALSE;
|
||||||
reset_param(dev);
|
reset_param(dev);
|
||||||
@@ -1405,34 +1390,26 @@ static void m_init_complete(struct fpi_ssm *ssm)
|
|||||||
fpi_ssm_free(ssm);
|
fpi_ssm_free(ssm);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dev_activate(struct fp_img_dev *idev, enum fp_imgdev_state state)
|
static int dev_activate(struct fp_img_dev *idev)
|
||||||
{
|
{
|
||||||
struct etes603_dev *dev = idev->priv;
|
struct etes603_dev *dev = FP_INSTANCE_DATA(FP_DEV(idev));
|
||||||
struct fpi_ssm *ssm;
|
fpi_ssm *ssm;
|
||||||
|
|
||||||
assert(dev);
|
g_assert(dev);
|
||||||
|
|
||||||
if (state != IMGDEV_STATE_AWAIT_FINGER_ON) {
|
|
||||||
fp_err("The driver is in an unexpected state: %d.", state);
|
|
||||||
fpi_imgdev_activate_complete(idev, 1);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Reset info and data */
|
/* Reset info and data */
|
||||||
dev->is_active = TRUE;
|
dev->is_active = TRUE;
|
||||||
|
|
||||||
if (dev->dcoffset == 0) {
|
if (dev->dcoffset == 0) {
|
||||||
fp_dbg("Tuning device...");
|
fp_dbg("Tuning device...");
|
||||||
ssm = fpi_ssm_new(idev->dev, m_init_state, INIT_NUM_STATES);
|
ssm = fpi_ssm_new(FP_DEV(idev), m_init_state, INIT_NUM_STATES, idev);
|
||||||
ssm->priv = idev;
|
|
||||||
fpi_ssm_start(ssm, m_init_complete);
|
fpi_ssm_start(ssm, m_init_complete);
|
||||||
} else {
|
} else {
|
||||||
fp_dbg("Using previous tuning (DCOFFSET=0x%02X,VRT=0x%02X,"
|
fp_dbg("Using previous tuning (DCOFFSET=0x%02X,VRT=0x%02X,"
|
||||||
"VRB=0x%02X,GAIN=0x%02X).", dev->dcoffset, dev->vrt,
|
"VRB=0x%02X,GAIN=0x%02X).", dev->dcoffset, dev->vrt,
|
||||||
dev->vrb, dev->gain);
|
dev->vrb, dev->gain);
|
||||||
fpi_imgdev_activate_complete(idev, 0);
|
fpi_imgdev_activate_complete(idev, 0);
|
||||||
ssm = fpi_ssm_new(idev->dev, m_finger_state, FGR_NUM_STATES);
|
ssm = fpi_ssm_new(FP_DEV(idev), m_finger_state, FGR_NUM_STATES, idev);
|
||||||
ssm->priv = idev;
|
|
||||||
fpi_ssm_start(ssm, m_finger_complete);
|
fpi_ssm_start(ssm, m_finger_complete);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1440,15 +1417,16 @@ static int dev_activate(struct fp_img_dev *idev, enum fp_imgdev_state state)
|
|||||||
|
|
||||||
static void dev_deactivate(struct fp_img_dev *idev)
|
static void dev_deactivate(struct fp_img_dev *idev)
|
||||||
{
|
{
|
||||||
struct etes603_dev *dev = idev->priv;
|
struct etes603_dev *dev = FP_INSTANCE_DATA(FP_DEV(idev));
|
||||||
|
|
||||||
fp_dbg("deactivating");
|
fp_dbg("deactivating");
|
||||||
|
|
||||||
/* this can be called even if still activated. */
|
/* this can be called even if still activated. */
|
||||||
if (dev->is_active == TRUE) {
|
if (dev->is_active == TRUE) {
|
||||||
dev->is_active = FALSE;
|
dev->is_active = FALSE;
|
||||||
m_exit_start(idev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_exit_start(idev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dev_open(struct fp_img_dev *idev, unsigned long driver_data)
|
static int dev_open(struct fp_img_dev *idev, unsigned long driver_data)
|
||||||
@@ -1457,16 +1435,15 @@ static int dev_open(struct fp_img_dev *idev, unsigned long driver_data)
|
|||||||
struct etes603_dev *dev;
|
struct etes603_dev *dev;
|
||||||
|
|
||||||
dev = g_malloc0(sizeof(struct etes603_dev));
|
dev = g_malloc0(sizeof(struct etes603_dev));
|
||||||
idev->priv = dev;
|
fp_dev_set_instance_data(FP_DEV(idev), dev);
|
||||||
|
|
||||||
dev->req = g_malloc(sizeof(struct egis_msg));
|
dev->req = g_malloc(sizeof(struct egis_msg));
|
||||||
dev->ans = g_malloc(FE_SIZE);
|
dev->ans = g_malloc(FE_SIZE);
|
||||||
dev->fp = g_malloc(FE_SIZE * 4);
|
dev->fp = g_malloc(FE_SIZE * 4);
|
||||||
|
|
||||||
ret = libusb_claim_interface(idev->udev, 0);
|
ret = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(idev)), 0);
|
||||||
if (ret != LIBUSB_SUCCESS) {
|
if (ret != LIBUSB_SUCCESS) {
|
||||||
fp_err("libusb_claim_interface failed on interface 0 "
|
fp_err("libusb_claim_interface failed on interface 0: %s", libusb_error_name(ret));
|
||||||
"(err=%d)", ret);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1476,14 +1453,14 @@ static int dev_open(struct fp_img_dev *idev, unsigned long driver_data)
|
|||||||
|
|
||||||
static void dev_close(struct fp_img_dev *idev)
|
static void dev_close(struct fp_img_dev *idev)
|
||||||
{
|
{
|
||||||
struct etes603_dev *dev = idev->priv;
|
struct etes603_dev *dev = FP_INSTANCE_DATA(FP_DEV(idev));
|
||||||
|
|
||||||
g_free(dev->req);
|
g_free(dev->req);
|
||||||
g_free(dev->ans);
|
g_free(dev->ans);
|
||||||
g_free(dev->fp);
|
g_free(dev->fp);
|
||||||
g_free(dev);
|
g_free(dev);
|
||||||
|
|
||||||
libusb_release_interface(idev->udev, 0);
|
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(idev)), 0);
|
||||||
fpi_imgdev_close_complete(idev);
|
fpi_imgdev_close_complete(idev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,323 +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
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include <libusb.h>
|
|
||||||
|
|
||||||
#define FP_COMPONENT "fdu2000"
|
|
||||||
#include <fp_internal.h>
|
|
||||||
|
|
||||||
#include "driver_ids.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(dev->udev, LED_ON))) {
|
|
||||||
fp_err("Command: LED_ON");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((r = bulk_write_safe(dev->udev, CAPTURE_READY))) {
|
|
||||||
fp_err("Command: CAPTURE_READY");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
read:
|
|
||||||
if ((r = bulk_write_safe(dev->udev, CAPTURE_READ))) {
|
|
||||||
fp_err("Command: CAPTURE_READ");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now we are ready to read from dev */
|
|
||||||
|
|
||||||
r = libusb_bulk_transfer(dev->udev, &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(dev->udev, CAPTURE_END))) {
|
|
||||||
fp_err("Command: CAPTURE_END");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((r = bulk_write_safe(dev->udev, 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(dev->udev, 1)) < 0 )
|
|
||||||
// goto out;
|
|
||||||
|
|
||||||
if ( (r = libusb_claim_interface(dev->udev, 0)) < 0 )
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
//if ( (r = usb_set_altinterface(dev->udev, 1)) < 0 )
|
|
||||||
// goto out;
|
|
||||||
|
|
||||||
//if ( (r = usb_clear_halt(dev->udev, EP_CMD)) < 0 )
|
|
||||||
// goto out;
|
|
||||||
|
|
||||||
/* Make sure sensor mode is not capture_{ready|read} */
|
|
||||||
if ((r = bulk_write_safe(dev->udev, CAPTURE_END))) {
|
|
||||||
fp_err("Command: CAPTURE_END");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((r = bulk_write_safe(dev->udev, 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(dev->udev, CAPTURE_END))
|
|
||||||
fp_err("Command: CAPTURE_END");
|
|
||||||
|
|
||||||
libusb_release_interface(dev->udev, 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,
|
|
||||||
};
|
|
||||||
66
libfprint/drivers/upek_proto.c
Normal file
66
libfprint/drivers/upek_proto.c
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
24
libfprint/drivers/upek_proto.h
Normal file
24
libfprint/drivers/upek_proto.h
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* 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);
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
319
libfprint/drivers/upeksonly.h
Normal file
319
libfprint/drivers/upeksonly.h
Normal file
@@ -0,0 +1,319 @@
|
|||||||
|
/*
|
||||||
|
* UPEK TouchStrip Sensor-Only driver for libfprint
|
||||||
|
* Copyright (C) 2008 Daniel Drake <dsd@gentoo.org>
|
||||||
|
*
|
||||||
|
* TCS4C (USB ID 147e:1000) support:
|
||||||
|
* Copyright (C) 2010 Hugo Grostabussiat <dw23.devel@gmail.com>
|
||||||
|
*
|
||||||
|
* TCRD5B (USB ID 147e:1001) support:
|
||||||
|
* Copyright (C) 2014 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 IMG_WIDTH_2016 288
|
||||||
|
#define IMG_WIDTH_1000 288
|
||||||
|
#define IMG_WIDTH_1001 216
|
||||||
|
|
||||||
|
struct sonly_regwrite {
|
||||||
|
uint8_t reg;
|
||||||
|
uint8_t value;
|
||||||
|
};
|
||||||
|
|
||||||
|
/***** AWAIT FINGER *****/
|
||||||
|
|
||||||
|
static const struct sonly_regwrite awfsm_2016_writev_1[] = {
|
||||||
|
{ 0x0a, 0x00 }, { 0x0a, 0x00 }, { 0x09, 0x20 }, { 0x03, 0x3b },
|
||||||
|
{ 0x00, 0x67 }, { 0x00, 0x67 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct sonly_regwrite awfsm_1000_writev_1[] = {
|
||||||
|
/* Initialize sensor settings */
|
||||||
|
{ 0x0a, 0x00 }, { 0x09, 0x20 }, { 0x03, 0x37 }, { 0x00, 0x5f },
|
||||||
|
{ 0x01, 0x6e }, { 0x01, 0xee }, { 0x0c, 0x13 }, { 0x0d, 0x0d },
|
||||||
|
{ 0x0e, 0x0e }, { 0x0f, 0x0d },
|
||||||
|
|
||||||
|
{ 0x13, 0x05 }, { 0x13, 0x45 },
|
||||||
|
|
||||||
|
/* Initialize finger detection registers (not enabling yet) */
|
||||||
|
{ 0x30, 0xe0 }, { 0x15, 0x26 },
|
||||||
|
|
||||||
|
{ 0x12, 0x01 }, { 0x20, 0x01 }, { 0x07, 0x10 },
|
||||||
|
{ 0x10, 0x00 }, { 0x11, 0xbf },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct sonly_regwrite awfsm_2016_writev_2[] = {
|
||||||
|
{ 0x01, 0xc6 }, { 0x0c, 0x13 }, { 0x0d, 0x0d }, { 0x0e, 0x0e },
|
||||||
|
{ 0x0f, 0x0d }, { 0x0b, 0x00 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct sonly_regwrite awfsm_1000_writev_2[] = {
|
||||||
|
/* Enable finger detection */
|
||||||
|
{ 0x30, 0xe1 }, { 0x15, 0x06 }, { 0x15, 0x86 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct sonly_regwrite awfsm_2016_writev_3[] = {
|
||||||
|
{ 0x13, 0x45 }, { 0x30, 0xe0 }, { 0x12, 0x01 }, { 0x20, 0x01 },
|
||||||
|
{ 0x09, 0x20 }, { 0x0a, 0x00 }, { 0x30, 0xe0 }, { 0x20, 0x01 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct sonly_regwrite awfsm_2016_writev_4[] = {
|
||||||
|
{ 0x08, 0x00 }, { 0x10, 0x00 }, { 0x12, 0x01 }, { 0x11, 0xbf },
|
||||||
|
{ 0x12, 0x01 }, { 0x07, 0x10 }, { 0x07, 0x10 }, { 0x04, 0x00 },\
|
||||||
|
{ 0x05, 0x00 }, { 0x0b, 0x00 },
|
||||||
|
|
||||||
|
/* enter finger detection mode */
|
||||||
|
{ 0x15, 0x20 }, { 0x30, 0xe1 }, { 0x15, 0x24 }, { 0x15, 0x04 },
|
||||||
|
{ 0x15, 0x84 },
|
||||||
|
};
|
||||||
|
|
||||||
|
/***** CAPTURE MODE *****/
|
||||||
|
|
||||||
|
static const struct sonly_regwrite capsm_2016_writev[] = {
|
||||||
|
/* enter capture mode */
|
||||||
|
{ 0x09, 0x28 }, { 0x13, 0x55 }, { 0x0b, 0x80 }, { 0x04, 0x00 },
|
||||||
|
{ 0x05, 0x00 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct sonly_regwrite capsm_1000_writev[] = {
|
||||||
|
{ 0x08, 0x80 }, { 0x13, 0x55 }, { 0x0b, 0x80 }, /* Enter capture mode */
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct sonly_regwrite capsm_1001_writev_1[] = {
|
||||||
|
{ 0x1a, 0x02 },
|
||||||
|
{ 0x4a, 0x9d },
|
||||||
|
{ 0x4e, 0x05 },
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static const struct sonly_regwrite capsm_1001_writev_2[] = {
|
||||||
|
{ 0x4d, 0xc0 }, { 0x4e, 0x09 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct sonly_regwrite capsm_1001_writev_3[] = {
|
||||||
|
{ 0x4a, 0x9c },
|
||||||
|
{ 0x1a, 0x00 },
|
||||||
|
{ 0x0b, 0x00 },
|
||||||
|
{ 0x04, 0x00 },
|
||||||
|
{ 0x05, 0x00 },
|
||||||
|
{ 0x1a, 0x02 },
|
||||||
|
{ 0x4a, 0x9d },
|
||||||
|
{ 0x4d, 0x40 }, { 0x4e, 0x09 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct sonly_regwrite capsm_1001_writev_4[] = {
|
||||||
|
{ 0x4a, 0x9c },
|
||||||
|
{ 0x1a, 0x00 },
|
||||||
|
{ 0x1a, 0x02 },
|
||||||
|
{ 0x4a, 0x9d },
|
||||||
|
{ 0x4e, 0x08 },
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static const struct sonly_regwrite capsm_1001_writev_5[] = {
|
||||||
|
{ 0x4a, 0x9c },
|
||||||
|
{ 0x1a, 0x00 },
|
||||||
|
{ 0x1a, 0x02 },
|
||||||
|
{ 0x00, 0x5f }, { 0x01, 0xee },
|
||||||
|
{ 0x03, 0x2c },
|
||||||
|
{ 0x07, 0x00 }, { 0x08, 0x00 }, { 0x09, 0x29 }, { 0x0a, 0x00 }, { 0x0b, 0x00 }, { 0x0c, 0x13 }, { 0x0d, 0x0d }, { 0x0e, 0x0e },
|
||||||
|
{ 0x0f, 0x0d }, { 0x10, 0x00 }, { 0x11, 0x8f }, { 0x12, 0x01 }, { 0x13, 0x45 },
|
||||||
|
{ 0x15, 0x26 },
|
||||||
|
{ 0x1e, 0x02 },
|
||||||
|
{ 0x20, 0x01 },
|
||||||
|
{ 0x25, 0x8f },
|
||||||
|
{ 0x27, 0x23 },
|
||||||
|
{ 0x30, 0xe0 },
|
||||||
|
{ 0x07, 0x10 },
|
||||||
|
{ 0x09, 0x21 },
|
||||||
|
{ 0x13, 0x75 },
|
||||||
|
{ 0x0b, 0x80 },
|
||||||
|
};
|
||||||
|
|
||||||
|
/***** DEINITIALIZATION *****/
|
||||||
|
|
||||||
|
static const struct sonly_regwrite deinitsm_2016_writev[] = {
|
||||||
|
/* reset + enter low power mode */
|
||||||
|
{ 0x0b, 0x00 }, { 0x09, 0x20 }, { 0x13, 0x45 }, { 0x13, 0x45 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct sonly_regwrite deinitsm_1000_writev[] = {
|
||||||
|
{ 0x15, 0x26 }, { 0x30, 0xe0 }, /* Disable finger detection */
|
||||||
|
|
||||||
|
{ 0x0b, 0x00 }, { 0x13, 0x45 }, { 0x08, 0x00 }, /* Disable capture mode */
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct sonly_regwrite deinitsm_1001_writev[] = {
|
||||||
|
{ 0x0b, 0x00 },
|
||||||
|
{ 0x13, 0x45 },
|
||||||
|
{ 0x09, 0x29 },
|
||||||
|
{ 0x1a, 0x00 },
|
||||||
|
};
|
||||||
|
|
||||||
|
/***** INITIALIZATION *****/
|
||||||
|
|
||||||
|
static const struct sonly_regwrite initsm_2016_writev_1[] = {
|
||||||
|
{ 0x49, 0x00 },
|
||||||
|
|
||||||
|
/* BSAPI writes different values to register 0x3e each time. I initially
|
||||||
|
* thought this was some kind of clever authentication, but just blasting
|
||||||
|
* these sniffed values each time seems to work. */
|
||||||
|
{ 0x3e, 0x83 }, { 0x3e, 0x4f }, { 0x3e, 0x0f }, { 0x3e, 0xbf },
|
||||||
|
{ 0x3e, 0x45 }, { 0x3e, 0x35 }, { 0x3e, 0x1c }, { 0x3e, 0xae },
|
||||||
|
|
||||||
|
{ 0x44, 0x01 }, { 0x43, 0x06 }, { 0x43, 0x05 }, { 0x43, 0x04 },
|
||||||
|
{ 0x44, 0x00 }, { 0x0b, 0x00 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct sonly_regwrite initsm_1000_writev_1[] = {
|
||||||
|
{ 0x49, 0x00 }, /* Encryption disabled */
|
||||||
|
|
||||||
|
/* Setting encryption key. Doesn't need to be random since we don't use any
|
||||||
|
* encryption. */
|
||||||
|
{ 0x3e, 0x7f }, { 0x3e, 0x7f }, { 0x3e, 0x7f }, { 0x3e, 0x7f },
|
||||||
|
{ 0x3e, 0x7f }, { 0x3e, 0x7f }, { 0x3e, 0x7f }, { 0x3e, 0x7f },
|
||||||
|
|
||||||
|
{ 0x04, 0x00 }, { 0x05, 0x00 },
|
||||||
|
|
||||||
|
{ 0x0b, 0x00 }, { 0x08, 0x00 }, /* Initialize capture control registers */
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct sonly_regwrite initsm_1001_writev_1[] = {
|
||||||
|
{ 0x4a, 0x9d },
|
||||||
|
{ 0x4f, 0x06 },
|
||||||
|
{ 0x4f, 0x05 },
|
||||||
|
{ 0x4f, 0x04 },
|
||||||
|
{ 0x4a, 0x9c },
|
||||||
|
{ 0x3e, 0xa6 },
|
||||||
|
{ 0x3e, 0x01 },
|
||||||
|
{ 0x3e, 0x68 },
|
||||||
|
{ 0x3e, 0xfd },
|
||||||
|
{ 0x3e, 0x72 },
|
||||||
|
{ 0x3e, 0xef },
|
||||||
|
{ 0x3e, 0x5d },
|
||||||
|
{ 0x3e, 0xc5 },
|
||||||
|
{ 0x1a, 0x02 },
|
||||||
|
{ 0x4a, 0x9d },
|
||||||
|
{ 0x4c, 0x1f }, { 0x4d, 0xb8 }, { 0x4e, 0x00 },
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static const struct sonly_regwrite initsm_1001_writev_2[] = {
|
||||||
|
{ 0x4c, 0x03 }, { 0x4d, 0xb8 }, { 0x4e, 0x00 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct sonly_regwrite initsm_1001_writev_3[] = {
|
||||||
|
{ 0x4a, 0x9c },
|
||||||
|
{ 0x1a, 0x00 },
|
||||||
|
{ 0x1a, 0x02 },
|
||||||
|
{ 0x4a, 0x9d },
|
||||||
|
{ 0x4c, 0xff }, { 0x4d, 0xc0 }, { 0x4e, 0x00 },
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static const struct sonly_regwrite initsm_1001_writev_4[] = {
|
||||||
|
{ 0x4a, 0x9c },
|
||||||
|
{ 0x1a, 0x00 },
|
||||||
|
{ 0x09, 0x27 },
|
||||||
|
{ 0x1a, 0x02 },
|
||||||
|
{ 0x49, 0x01 },
|
||||||
|
{ 0x47, 0x02 },
|
||||||
|
{ 0x47, 0x02 },
|
||||||
|
{ 0x47, 0x02 },
|
||||||
|
{ 0x47, 0x02 },
|
||||||
|
{ 0x47, 0x02 },
|
||||||
|
{ 0x47, 0x02 },
|
||||||
|
{ 0x47, 0x02 },
|
||||||
|
{ 0x47, 0x0a },
|
||||||
|
{ 0x47, 0x00 },
|
||||||
|
{ 0x47, 0x04 },
|
||||||
|
{ 0x47, 0x04 },
|
||||||
|
{ 0x47, 0x04 },
|
||||||
|
{ 0x47, 0x04 },
|
||||||
|
{ 0x47, 0x04 },
|
||||||
|
{ 0x47, 0x04 },
|
||||||
|
{ 0x47, 0x04 },
|
||||||
|
{ 0x47, 0x04 },
|
||||||
|
{ 0x47, 0x02 },
|
||||||
|
{ 0x47, 0x02 },
|
||||||
|
{ 0x47, 0x02 },
|
||||||
|
{ 0x47, 0x02 },
|
||||||
|
{ 0x47, 0x02 },
|
||||||
|
{ 0x47, 0x02 },
|
||||||
|
{ 0x47, 0x02 },
|
||||||
|
{ 0x47, 0x0a },
|
||||||
|
{ 0x47, 0x00 },
|
||||||
|
{ 0x47, 0x04 },
|
||||||
|
{ 0x47, 0x04 },
|
||||||
|
{ 0x47, 0x04 },
|
||||||
|
{ 0x47, 0x04 },
|
||||||
|
{ 0x47, 0x04 },
|
||||||
|
{ 0x47, 0x04 },
|
||||||
|
{ 0x47, 0x04 },
|
||||||
|
{ 0x47, 0x04 },
|
||||||
|
{ 0x47, 0x02 },
|
||||||
|
{ 0x47, 0x02 },
|
||||||
|
{ 0x47, 0x02 },
|
||||||
|
{ 0x47, 0x02 },
|
||||||
|
{ 0x47, 0x02 },
|
||||||
|
{ 0x47, 0x02 },
|
||||||
|
{ 0x47, 0x02 },
|
||||||
|
{ 0x47, 0x0a },
|
||||||
|
{ 0x47, 0x00 },
|
||||||
|
{ 0x47, 0x04 },
|
||||||
|
{ 0x47, 0x04 },
|
||||||
|
{ 0x47, 0x04 },
|
||||||
|
{ 0x47, 0x04 },
|
||||||
|
{ 0x47, 0x04 },
|
||||||
|
{ 0x47, 0x04 },
|
||||||
|
{ 0x47, 0x04 },
|
||||||
|
{ 0x47, 0x04 },
|
||||||
|
{ 0x47, 0x02 },
|
||||||
|
{ 0x47, 0x02 },
|
||||||
|
{ 0x47, 0x02 },
|
||||||
|
{ 0x47, 0x02 },
|
||||||
|
{ 0x47, 0x02 },
|
||||||
|
{ 0x47, 0x02 },
|
||||||
|
{ 0x47, 0x02 },
|
||||||
|
{ 0x47, 0x0a },
|
||||||
|
{ 0x47, 0x00 },
|
||||||
|
{ 0x47, 0x04 },
|
||||||
|
{ 0x47, 0x04 },
|
||||||
|
{ 0x47, 0x04 },
|
||||||
|
{ 0x47, 0x04 },
|
||||||
|
{ 0x47, 0x04 },
|
||||||
|
{ 0x47, 0x04 },
|
||||||
|
{ 0x47, 0x04 },
|
||||||
|
{ 0x47, 0x04 },
|
||||||
|
{ 0x49, 0x00 },
|
||||||
|
{ 0x3e, 0x90 },
|
||||||
|
{ 0x3e, 0xbd },
|
||||||
|
{ 0x3e, 0xbf },
|
||||||
|
{ 0x3e, 0x48 },
|
||||||
|
{ 0x3e, 0x2a },
|
||||||
|
{ 0x3e, 0xe3 },
|
||||||
|
{ 0x3e, 0xd2 },
|
||||||
|
{ 0x3e, 0x58 },
|
||||||
|
{ 0x09, 0x2f },
|
||||||
|
{ 0x1a, 0x00 },
|
||||||
|
{ 0x1a, 0x02 },
|
||||||
|
{ 0x4a, 0x9d },
|
||||||
|
{ 0x4d, 0x40 }, { 0x4e, 0x03 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct sonly_regwrite initsm_1001_writev_5[] = {
|
||||||
|
{ 0x4a, 0x9c },
|
||||||
|
{ 0x1a, 0x00 },
|
||||||
|
};
|
||||||
@@ -20,13 +20,8 @@
|
|||||||
|
|
||||||
#define FP_COMPONENT "upektc"
|
#define FP_COMPONENT "upektc"
|
||||||
|
|
||||||
#include <errno.h>
|
#include "drivers_api.h"
|
||||||
#include <string.h>
|
|
||||||
#include <libusb.h>
|
|
||||||
#include <fp_internal.h>
|
|
||||||
|
|
||||||
#include "upektc.h"
|
#include "upektc.h"
|
||||||
#include "driver_ids.h"
|
|
||||||
|
|
||||||
#define UPEKTC_EP_IN (2 | LIBUSB_ENDPOINT_IN)
|
#define UPEKTC_EP_IN (2 | LIBUSB_ENDPOINT_IN)
|
||||||
#define UPEKTC_EP_OUT (3 | LIBUSB_ENDPOINT_OUT)
|
#define UPEKTC_EP_OUT (3 | LIBUSB_ENDPOINT_OUT)
|
||||||
@@ -61,10 +56,11 @@ 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(fpi_ssm *ssm,
|
||||||
|
struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
struct upektc_dev *upekdev = dev->priv;
|
|
||||||
|
|
||||||
upekdev->init_idx += 1;
|
upekdev->init_idx += 1;
|
||||||
if (upekdev->init_idx == upekdev->setup_commands_len)
|
if (upekdev->init_idx == upekdev->setup_commands_len)
|
||||||
@@ -75,70 +71,63 @@ static void upektc_next_init_cmd(struct fpi_ssm *ssm)
|
|||||||
|
|
||||||
static void write_init_cb(struct libusb_transfer *transfer)
|
static void write_init_cb(struct libusb_transfer *transfer)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
||||||
struct upektc_dev *upekdev = dev->priv;
|
struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
|
||||||
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
|
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
|
||||||
(transfer->length == transfer->actual_length)) {
|
(transfer->length == transfer->actual_length)) {
|
||||||
if (upekdev->setup_commands[upekdev->init_idx].response_len)
|
if (upekdev->setup_commands[upekdev->init_idx].response_len)
|
||||||
fpi_ssm_next_state(ssm);
|
fpi_ssm_next_state(ssm);
|
||||||
else
|
else
|
||||||
upektc_next_init_cmd(ssm);
|
upektc_next_init_cmd(ssm, dev);
|
||||||
} else {
|
} else {
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
}
|
}
|
||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void read_init_data_cb(struct libusb_transfer *transfer)
|
static void read_init_data_cb(struct libusb_transfer *transfer)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
|
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
||||||
|
|
||||||
if (transfer->status == LIBUSB_TRANSFER_COMPLETED)
|
if (transfer->status == LIBUSB_TRANSFER_COMPLETED)
|
||||||
upektc_next_init_cmd(ssm);
|
upektc_next_init_cmd(ssm, dev);
|
||||||
else
|
else
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
g_free(transfer->buffer);
|
g_free(transfer->buffer);
|
||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void activate_run_state(struct fpi_ssm *ssm)
|
static void activate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = user_data;
|
||||||
struct upektc_dev *upekdev = dev->priv;
|
struct upektc_dev *upekdev = FP_INSTANCE_DATA(_dev);
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
switch (ssm->cur_state) {
|
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||||
case WRITE_INIT:
|
case WRITE_INIT:
|
||||||
{
|
{
|
||||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||||
if (!transfer) {
|
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), upekdev->ep_out,
|
||||||
return;
|
|
||||||
}
|
|
||||||
libusb_fill_bulk_transfer(transfer, dev->udev, upekdev->ep_out,
|
|
||||||
(unsigned char*)upekdev->setup_commands[upekdev->init_idx].cmd,
|
(unsigned char*)upekdev->setup_commands[upekdev->init_idx].cmd,
|
||||||
UPEKTC_CMD_LEN, write_init_cb, ssm, BULK_TIMEOUT);
|
UPEKTC_CMD_LEN, write_init_cb, ssm, BULK_TIMEOUT);
|
||||||
r = libusb_submit_transfer(transfer);
|
r = libusb_submit_transfer(transfer);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
fpi_ssm_mark_failed(ssm, -ENOMEM);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case READ_DATA:
|
case READ_DATA:
|
||||||
{
|
{
|
||||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||||
unsigned char *data;
|
unsigned char *data;
|
||||||
|
|
||||||
if (!transfer) {
|
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
data = g_malloc(upekdev->setup_commands[upekdev->init_idx].response_len);
|
data = g_malloc(upekdev->setup_commands[upekdev->init_idx].response_len);
|
||||||
libusb_fill_bulk_transfer(transfer, dev->udev, upekdev->ep_in, data,
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), upekdev->ep_in, data,
|
||||||
upekdev->setup_commands[upekdev->init_idx].response_len,
|
upekdev->setup_commands[upekdev->init_idx].response_len,
|
||||||
read_init_data_cb, ssm, BULK_TIMEOUT);
|
read_init_data_cb, ssm, BULK_TIMEOUT);
|
||||||
|
|
||||||
@@ -146,20 +135,20 @@ static void activate_run_state(struct fpi_ssm *ssm)
|
|||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
g_free(data);
|
g_free(data);
|
||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
fpi_ssm_mark_aborted(ssm, r);
|
fpi_ssm_mark_failed(ssm, r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void activate_sm_complete(struct fpi_ssm *ssm)
|
static void activate_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = user_data;
|
||||||
fp_dbg("status %d", ssm->error);
|
fp_dbg("status %d", fpi_ssm_get_error(ssm));
|
||||||
fpi_imgdev_activate_complete(dev, ssm->error);
|
fpi_imgdev_activate_complete(dev, fpi_ssm_get_error(ssm));
|
||||||
|
|
||||||
if (!ssm->error)
|
if (!fpi_ssm_get_error(ssm))
|
||||||
start_finger_detection(dev);
|
start_finger_detection(dev);
|
||||||
fpi_ssm_free(ssm);
|
fpi_ssm_free(ssm);
|
||||||
}
|
}
|
||||||
@@ -186,7 +175,7 @@ static int finger_present(unsigned char *img, size_t len, int sum_threshold)
|
|||||||
static void finger_det_data_cb(struct libusb_transfer *transfer)
|
static void finger_det_data_cb(struct libusb_transfer *transfer)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = transfer->user_data;
|
struct fp_img_dev *dev = transfer->user_data;
|
||||||
struct upektc_dev *upekdev = dev->priv;
|
struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
unsigned char *data = transfer->buffer;
|
unsigned char *data = transfer->buffer;
|
||||||
|
|
||||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||||
@@ -219,7 +208,7 @@ static void finger_det_cmd_cb(struct libusb_transfer *t)
|
|||||||
unsigned char *data;
|
unsigned char *data;
|
||||||
int r;
|
int r;
|
||||||
struct fp_img_dev *dev = t->user_data;
|
struct fp_img_dev *dev = t->user_data;
|
||||||
struct upektc_dev *upekdev = dev->priv;
|
struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
|
||||||
if (t->status != LIBUSB_TRANSFER_COMPLETED) {
|
if (t->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||||
fp_dbg("req transfer status %d\n", t->status);
|
fp_dbg("req transfer status %d\n", t->status);
|
||||||
@@ -231,14 +220,9 @@ static void finger_det_cmd_cb(struct libusb_transfer *t)
|
|||||||
goto exit_free_transfer;
|
goto exit_free_transfer;
|
||||||
}
|
}
|
||||||
|
|
||||||
transfer = libusb_alloc_transfer(0);
|
transfer = fpi_usb_alloc();
|
||||||
if (!transfer) {
|
|
||||||
fpi_imgdev_session_error(dev, -ENOMEM);
|
|
||||||
goto exit_free_transfer;
|
|
||||||
}
|
|
||||||
|
|
||||||
data = g_malloc(IMAGE_SIZE);
|
data = g_malloc(IMAGE_SIZE);
|
||||||
libusb_fill_bulk_transfer(transfer, dev->udev, upekdev->ep_in, data, IMAGE_SIZE,
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), upekdev->ep_in, data, IMAGE_SIZE,
|
||||||
finger_det_data_cb, dev, BULK_TIMEOUT);
|
finger_det_data_cb, dev, BULK_TIMEOUT);
|
||||||
|
|
||||||
r = libusb_submit_transfer(transfer);
|
r = libusb_submit_transfer(transfer);
|
||||||
@@ -254,21 +238,17 @@ exit_free_transfer:
|
|||||||
static void start_finger_detection(struct fp_img_dev *dev)
|
static void start_finger_detection(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
struct upektc_dev *upekdev = dev->priv;
|
struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
struct libusb_transfer *transfer;
|
struct libusb_transfer *transfer;
|
||||||
fp_dbg("");
|
G_DEBUG_HERE();
|
||||||
|
|
||||||
if (upekdev->deactivating) {
|
if (upekdev->deactivating) {
|
||||||
complete_deactivation(dev);
|
complete_deactivation(dev);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
transfer = libusb_alloc_transfer(0);
|
transfer = fpi_usb_alloc();
|
||||||
if (!transfer) {
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), upekdev->ep_out,
|
||||||
fpi_imgdev_session_error(dev, -ENOMEM);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
libusb_fill_bulk_transfer(transfer, dev->udev, upekdev->ep_out,
|
|
||||||
(unsigned char *)scan_cmd, UPEKTC_CMD_LEN,
|
(unsigned char *)scan_cmd, UPEKTC_CMD_LEN,
|
||||||
finger_det_cmd_cb, dev, BULK_TIMEOUT);
|
finger_det_cmd_cb, dev, BULK_TIMEOUT);
|
||||||
r = libusb_submit_transfer(transfer);
|
r = libusb_submit_transfer(transfer);
|
||||||
@@ -288,31 +268,31 @@ enum capture_states {
|
|||||||
|
|
||||||
static void capture_cmd_cb(struct libusb_transfer *transfer)
|
static void capture_cmd_cb(struct libusb_transfer *transfer)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
|
|
||||||
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
|
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
|
||||||
(transfer->length == transfer->actual_length)) {
|
(transfer->length == transfer->actual_length)) {
|
||||||
fpi_ssm_next_state(ssm);
|
fpi_ssm_next_state(ssm);
|
||||||
} else {
|
} else {
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
}
|
}
|
||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void capture_read_data_cb(struct libusb_transfer *transfer)
|
static void capture_read_data_cb(struct libusb_transfer *transfer)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
||||||
unsigned char *data = transfer->buffer;
|
unsigned char *data = transfer->buffer;
|
||||||
struct fp_img *img;
|
struct fp_img *img;
|
||||||
|
|
||||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||||
fp_dbg("request is not completed, %d", transfer->status);
|
fp_dbg("request is not completed, %d", transfer->status);
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
goto out;
|
goto out;
|
||||||
} else if (transfer->length != transfer->actual_length) {
|
} else if (transfer->length != transfer->actual_length) {
|
||||||
fp_dbg("expected %d, sent %d bytes", transfer->length, transfer->actual_length);
|
fp_dbg("expected %d, sent %d bytes", transfer->length, transfer->actual_length);
|
||||||
fpi_ssm_mark_aborted(ssm, -EPROTO);
|
fpi_ssm_mark_failed(ssm, -EPROTO);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -326,65 +306,57 @@ out:
|
|||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void capture_run_state(struct fpi_ssm *ssm)
|
static void capture_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = user_data;
|
||||||
struct upektc_dev *upekdev = dev->priv;
|
struct upektc_dev *upekdev = FP_INSTANCE_DATA(_dev);
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
switch (ssm->cur_state) {
|
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||||
case CAPTURE_WRITE_CMD:
|
case CAPTURE_WRITE_CMD:
|
||||||
{
|
{
|
||||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||||
if (!transfer) {
|
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), upekdev->ep_out,
|
||||||
return;
|
|
||||||
}
|
|
||||||
libusb_fill_bulk_transfer(transfer, dev->udev, upekdev->ep_out,
|
|
||||||
(unsigned char *)scan_cmd, UPEKTC_CMD_LEN,
|
(unsigned char *)scan_cmd, UPEKTC_CMD_LEN,
|
||||||
capture_cmd_cb, ssm, BULK_TIMEOUT);
|
capture_cmd_cb, ssm, BULK_TIMEOUT);
|
||||||
r = libusb_submit_transfer(transfer);
|
r = libusb_submit_transfer(transfer);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
fpi_ssm_mark_failed(ssm, -ENOMEM);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CAPTURE_READ_DATA:
|
case CAPTURE_READ_DATA:
|
||||||
{
|
{
|
||||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||||
unsigned char *data;
|
unsigned char *data;
|
||||||
|
|
||||||
if (!transfer) {
|
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
data = g_malloc(IMAGE_SIZE);
|
data = g_malloc(IMAGE_SIZE);
|
||||||
libusb_fill_bulk_transfer(transfer, dev->udev, upekdev->ep_in, data, IMAGE_SIZE,
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), upekdev->ep_in, data, IMAGE_SIZE,
|
||||||
capture_read_data_cb, ssm, BULK_TIMEOUT);
|
capture_read_data_cb, ssm, BULK_TIMEOUT);
|
||||||
|
|
||||||
r = libusb_submit_transfer(transfer);
|
r = libusb_submit_transfer(transfer);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
g_free(data);
|
g_free(data);
|
||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
fpi_ssm_mark_aborted(ssm, r);
|
fpi_ssm_mark_failed(ssm, r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static void capture_sm_complete(struct fpi_ssm *ssm)
|
static void capture_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = user_data;
|
||||||
struct upektc_dev *upekdev = dev->priv;
|
struct upektc_dev *upekdev = FP_INSTANCE_DATA(_dev);
|
||||||
|
|
||||||
fp_dbg("Capture completed");
|
fp_dbg("Capture completed");
|
||||||
if (upekdev->deactivating)
|
if (upekdev->deactivating)
|
||||||
complete_deactivation(dev);
|
complete_deactivation(dev);
|
||||||
else if (ssm->error)
|
else if (fpi_ssm_get_error(ssm))
|
||||||
fpi_imgdev_session_error(dev, ssm->error);
|
fpi_imgdev_session_error(dev, fpi_ssm_get_error(ssm));
|
||||||
else
|
else
|
||||||
start_finger_detection(dev);
|
start_finger_detection(dev);
|
||||||
fpi_ssm_free(ssm);
|
fpi_ssm_free(ssm);
|
||||||
@@ -392,26 +364,24 @@ static void capture_sm_complete(struct fpi_ssm *ssm)
|
|||||||
|
|
||||||
static void start_capture(struct fp_img_dev *dev)
|
static void start_capture(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct upektc_dev *upekdev = dev->priv;
|
struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
struct fpi_ssm *ssm;
|
fpi_ssm *ssm;
|
||||||
|
|
||||||
if (upekdev->deactivating) {
|
if (upekdev->deactivating) {
|
||||||
complete_deactivation(dev);
|
complete_deactivation(dev);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssm = fpi_ssm_new(dev->dev, capture_run_state, CAPTURE_NUM_STATES);
|
ssm = fpi_ssm_new(FP_DEV(dev), capture_run_state, CAPTURE_NUM_STATES, dev);
|
||||||
fp_dbg("");
|
G_DEBUG_HERE();
|
||||||
ssm->priv = 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 int dev_activate(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct upektc_dev *upekdev = dev->priv;
|
struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
struct fpi_ssm *ssm = fpi_ssm_new(dev->dev, activate_run_state,
|
fpi_ssm *ssm = fpi_ssm_new(FP_DEV(dev), activate_run_state,
|
||||||
ACTIVATE_NUM_STATES);
|
ACTIVATE_NUM_STATES, dev);
|
||||||
ssm->priv = dev;
|
|
||||||
upekdev->init_idx = 0;
|
upekdev->init_idx = 0;
|
||||||
fpi_ssm_start(ssm, activate_sm_complete);
|
fpi_ssm_start(ssm, activate_sm_complete);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -419,15 +389,15 @@ static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
|||||||
|
|
||||||
static void dev_deactivate(struct fp_img_dev *dev)
|
static void dev_deactivate(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct upektc_dev *upekdev = dev->priv;
|
struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
|
||||||
upekdev->deactivating = TRUE;
|
upekdev->deactivating = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void complete_deactivation(struct fp_img_dev *dev)
|
static void complete_deactivation(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct upektc_dev *upekdev = dev->priv;
|
struct upektc_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
fp_dbg("");
|
G_DEBUG_HERE();
|
||||||
|
|
||||||
upekdev->deactivating = FALSE;
|
upekdev->deactivating = FALSE;
|
||||||
fpi_imgdev_deactivate_complete(dev);
|
fpi_imgdev_deactivate_complete(dev);
|
||||||
@@ -439,32 +409,33 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
|||||||
int r;
|
int r;
|
||||||
struct upektc_dev *upekdev;
|
struct upektc_dev *upekdev;
|
||||||
|
|
||||||
r = libusb_claim_interface(dev->udev, 0);
|
r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
fp_err("could not claim interface 0");
|
fp_err("could not claim interface 0: %s", libusb_error_name(r));
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev->priv = upekdev = g_malloc0(sizeof(struct upektc_dev));
|
upekdev = g_malloc0(sizeof(struct upektc_dev));
|
||||||
|
fp_dev_set_instance_data(FP_DEV(dev), upekdev);
|
||||||
switch (driver_data) {
|
switch (driver_data) {
|
||||||
case UPEKTC_2015:
|
case UPEKTC_2015:
|
||||||
upekdev->ep_in = UPEKTC_EP_IN;
|
upekdev->ep_in = UPEKTC_EP_IN;
|
||||||
upekdev->ep_out = UPEKTC_EP_OUT;
|
upekdev->ep_out = UPEKTC_EP_OUT;
|
||||||
upekdev->setup_commands = upektc_setup_commands;
|
upekdev->setup_commands = upektc_setup_commands;
|
||||||
upekdev->setup_commands_len = array_n_elements(upektc_setup_commands);
|
upekdev->setup_commands_len = G_N_ELEMENTS(upektc_setup_commands);
|
||||||
upekdev->sum_threshold = UPEKTC_SUM_THRESHOLD;
|
upekdev->sum_threshold = UPEKTC_SUM_THRESHOLD;
|
||||||
break;
|
break;
|
||||||
case UPEKTC_3001:
|
case UPEKTC_3001:
|
||||||
upekdev->ep_in = UPEKET_EP_IN;
|
upekdev->ep_in = UPEKET_EP_IN;
|
||||||
upekdev->ep_out = UPEKET_EP_OUT;
|
upekdev->ep_out = UPEKET_EP_OUT;
|
||||||
upekdev->setup_commands = upeket_setup_commands;
|
upekdev->setup_commands = upeket_setup_commands;
|
||||||
upekdev->setup_commands_len = array_n_elements(upeket_setup_commands);
|
upekdev->setup_commands_len = G_N_ELEMENTS(upeket_setup_commands);
|
||||||
upekdev->sum_threshold = UPEKET_SUM_THRESHOLD;
|
upekdev->sum_threshold = UPEKET_SUM_THRESHOLD;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fp_err("Device variant %d is not known\n", driver_data);
|
fp_err("Device variant %lu is not known\n", driver_data);
|
||||||
g_free(upekdev);
|
g_free(upekdev);
|
||||||
dev->priv = NULL;
|
fp_dev_set_instance_data(FP_DEV(dev), NULL);
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -474,8 +445,10 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
|||||||
|
|
||||||
static void dev_deinit(struct fp_img_dev *dev)
|
static void dev_deinit(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
g_free(dev->priv);
|
void *user_data;
|
||||||
libusb_release_interface(dev->udev, 0);
|
user_data = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
g_free(user_data);
|
||||||
|
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||||
fpi_imgdev_close_complete(dev);
|
fpi_imgdev_close_complete(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,18 +17,12 @@
|
|||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define FP_COMPONENT "upekts_img"
|
#define FP_COMPONENT "upektc_img"
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <libusb.h>
|
|
||||||
|
|
||||||
#include <aeslib.h>
|
|
||||||
#include <fp_internal.h>
|
|
||||||
|
|
||||||
|
#include "drivers_api.h"
|
||||||
|
#include "upek_proto.h"
|
||||||
|
#include "aeslib.h"
|
||||||
#include "upektc_img.h"
|
#include "upektc_img.h"
|
||||||
#include "driver_ids.h"
|
|
||||||
|
|
||||||
static void start_capture(struct fp_img_dev *dev);
|
static void start_capture(struct fp_img_dev *dev);
|
||||||
static void start_deactivation(struct fp_img_dev *dev);
|
static void start_deactivation(struct fp_img_dev *dev);
|
||||||
@@ -46,7 +40,7 @@ static void start_deactivation(struct fp_img_dev *dev);
|
|||||||
#define MAX_RESPONSE_SIZE 2052
|
#define MAX_RESPONSE_SIZE 2052
|
||||||
#define SHORT_RESPONSE_SIZE 64
|
#define SHORT_RESPONSE_SIZE 64
|
||||||
|
|
||||||
struct upekts_img_dev {
|
struct upektc_img_dev {
|
||||||
unsigned char cmd[MAX_CMD_SIZE];
|
unsigned char cmd[MAX_CMD_SIZE];
|
||||||
unsigned char response[MAX_RESPONSE_SIZE];
|
unsigned char response[MAX_RESPONSE_SIZE];
|
||||||
unsigned char image_bits[IMAGE_SIZE * 2];
|
unsigned char image_bits[IMAGE_SIZE * 2];
|
||||||
@@ -58,50 +52,6 @@ struct upekts_img_dev {
|
|||||||
|
|
||||||
/****** HELPERS ******/
|
/****** HELPERS ******/
|
||||||
|
|
||||||
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
|
|
||||||
};
|
|
||||||
|
|
||||||
static 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void upektc_img_cmd_fix_seq(unsigned char *cmd_buf, unsigned char seq)
|
static void upektc_img_cmd_fix_seq(unsigned char *cmd_buf, unsigned char seq)
|
||||||
{
|
{
|
||||||
uint8_t byte;
|
uint8_t byte;
|
||||||
@@ -121,61 +71,58 @@ static void upektc_img_cmd_update_crc(unsigned char *cmd_buf, size_t size)
|
|||||||
cmd_buf[size - 1] = (crc & 0xff00) >> 8;
|
cmd_buf[size - 1] = (crc & 0xff00) >> 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void upektc_img_submit_req(struct fpi_ssm *ssm,
|
static void
|
||||||
const unsigned char *buf, size_t buf_size, unsigned char seq,
|
upektc_img_submit_req(fpi_ssm *ssm,
|
||||||
libusb_transfer_cb_fn cb)
|
struct fp_img_dev *dev,
|
||||||
|
const unsigned char *buf,
|
||||||
|
size_t buf_size,
|
||||||
|
unsigned char seq,
|
||||||
|
libusb_transfer_cb_fn cb)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
struct upekts_img_dev *upekdev = dev->priv;
|
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
BUG_ON(buf_size > MAX_CMD_SIZE);
|
BUG_ON(buf_size > MAX_CMD_SIZE);
|
||||||
|
|
||||||
if (!transfer) {
|
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
transfer->flags |= LIBUSB_TRANSFER_FREE_TRANSFER;
|
transfer->flags |= LIBUSB_TRANSFER_FREE_TRANSFER;
|
||||||
|
|
||||||
memcpy(upekdev->cmd, buf, buf_size);
|
memcpy(upekdev->cmd, buf, buf_size);
|
||||||
upektc_img_cmd_fix_seq(upekdev->cmd, seq);
|
upektc_img_cmd_fix_seq(upekdev->cmd, seq);
|
||||||
upektc_img_cmd_update_crc(upekdev->cmd, buf_size);
|
upektc_img_cmd_update_crc(upekdev->cmd, buf_size);
|
||||||
|
|
||||||
libusb_fill_bulk_transfer(transfer, dev->udev, EP_OUT, upekdev->cmd, buf_size,
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_OUT, upekdev->cmd, buf_size,
|
||||||
cb, ssm, BULK_TIMEOUT);
|
cb, ssm, BULK_TIMEOUT);
|
||||||
|
|
||||||
r = libusb_submit_transfer(transfer);
|
r = libusb_submit_transfer(transfer);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
fpi_ssm_mark_aborted(ssm, r);
|
fpi_ssm_mark_failed(ssm, r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void upektc_img_read_data(struct fpi_ssm *ssm, size_t buf_size, size_t buf_offset, libusb_transfer_cb_fn cb)
|
static void
|
||||||
|
upektc_img_read_data(fpi_ssm *ssm,
|
||||||
|
struct fp_img_dev *dev,
|
||||||
|
size_t buf_size,
|
||||||
|
size_t buf_offset,
|
||||||
|
libusb_transfer_cb_fn cb)
|
||||||
{
|
{
|
||||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
struct upekts_img_dev *upekdev = dev->priv;
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (!transfer) {
|
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
BUG_ON(buf_size > MAX_RESPONSE_SIZE);
|
BUG_ON(buf_size > MAX_RESPONSE_SIZE);
|
||||||
|
|
||||||
transfer->flags |= LIBUSB_TRANSFER_FREE_TRANSFER;
|
transfer->flags |= LIBUSB_TRANSFER_FREE_TRANSFER;
|
||||||
|
|
||||||
libusb_fill_bulk_transfer(transfer, dev->udev, EP_IN, upekdev->response + buf_offset, buf_size,
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN, upekdev->response + buf_offset, buf_size,
|
||||||
cb, ssm, BULK_TIMEOUT);
|
cb, ssm, BULK_TIMEOUT);
|
||||||
|
|
||||||
r = libusb_submit_transfer(transfer);
|
r = libusb_submit_transfer(transfer);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
fpi_ssm_mark_aborted(ssm, r);
|
fpi_ssm_mark_failed(ssm, r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,21 +131,30 @@ static void upektc_img_read_data(struct fpi_ssm *ssm, size_t buf_size, size_t bu
|
|||||||
enum capture_states {
|
enum capture_states {
|
||||||
CAPTURE_INIT_CAPTURE,
|
CAPTURE_INIT_CAPTURE,
|
||||||
CAPTURE_READ_DATA,
|
CAPTURE_READ_DATA,
|
||||||
|
CAPTURE_READ_DATA_TERM,
|
||||||
CAPTURE_ACK_00_28,
|
CAPTURE_ACK_00_28,
|
||||||
CAPTURE_ACK_08,
|
CAPTURE_ACK_08,
|
||||||
CAPTURE_ACK_FRAME,
|
CAPTURE_ACK_FRAME,
|
||||||
|
CAPTURE_ACK_00_28_TERM,
|
||||||
CAPTURE_NUM_STATES,
|
CAPTURE_NUM_STATES,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void capture_reqs_cb(struct libusb_transfer *transfer)
|
static void capture_reqs_cb(struct libusb_transfer *transfer)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
|
|
||||||
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
|
if ((transfer->status != LIBUSB_TRANSFER_COMPLETED) ||
|
||||||
(transfer->length == transfer->actual_length)) {
|
(transfer->length != transfer->actual_length)) {
|
||||||
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||||
|
case CAPTURE_ACK_00_28_TERM:
|
||||||
|
fpi_ssm_jump_to_state(ssm, CAPTURE_READ_DATA_TERM);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
fpi_ssm_jump_to_state(ssm, CAPTURE_READ_DATA);
|
fpi_ssm_jump_to_state(ssm, CAPTURE_READ_DATA);
|
||||||
} else {
|
break;
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -222,16 +178,16 @@ static int upektc_img_process_image_frame(unsigned char *image_buf, unsigned cha
|
|||||||
|
|
||||||
static void capture_read_data_cb(struct libusb_transfer *transfer)
|
static void capture_read_data_cb(struct libusb_transfer *transfer)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
||||||
struct upekts_img_dev *upekdev = dev->priv;
|
struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
unsigned char *data = upekdev->response;
|
unsigned char *data = upekdev->response;
|
||||||
struct fp_img *img;
|
struct fp_img *img;
|
||||||
size_t response_size;
|
size_t response_size;
|
||||||
|
|
||||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||||
fp_dbg("request is not completed, %d", transfer->status);
|
fp_dbg("request is not completed, %d", transfer->status);
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,7 +199,13 @@ static void capture_read_data_cb(struct libusb_transfer *transfer)
|
|||||||
|
|
||||||
fp_dbg("request completed, len: %.4x", transfer->actual_length);
|
fp_dbg("request completed, len: %.4x", transfer->actual_length);
|
||||||
if (transfer->actual_length == 0) {
|
if (transfer->actual_length == 0) {
|
||||||
fpi_ssm_jump_to_state(ssm, CAPTURE_READ_DATA);
|
fpi_ssm_jump_to_state(ssm, fpi_ssm_get_cur_state(ssm));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fpi_ssm_get_cur_state(ssm) == CAPTURE_READ_DATA_TERM) {
|
||||||
|
fp_dbg("Terminating SSM\n");
|
||||||
|
fpi_ssm_mark_completed(ssm);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,7 +213,7 @@ static void capture_read_data_cb(struct libusb_transfer *transfer)
|
|||||||
response_size = ((data[5] & 0x0f) << 8) + data[6];
|
response_size = ((data[5] & 0x0f) << 8) + data[6];
|
||||||
response_size += 9; /* 7 bytes for header, 2 for CRC */
|
response_size += 9; /* 7 bytes for header, 2 for CRC */
|
||||||
if (response_size > transfer->actual_length) {
|
if (response_size > transfer->actual_length) {
|
||||||
fp_dbg("response_size is %d, actual_length is %d\n",
|
fp_dbg("response_size is %lu, actual_length is %d\n",
|
||||||
response_size, transfer->actual_length);
|
response_size, transfer->actual_length);
|
||||||
fp_dbg("Waiting for rest of transfer");
|
fp_dbg("Waiting for rest of transfer");
|
||||||
BUG_ON(upekdev->response_rest);
|
BUG_ON(upekdev->response_rest);
|
||||||
@@ -277,10 +239,26 @@ static void capture_read_data_cb(struct libusb_transfer *transfer)
|
|||||||
/* finger is present! */
|
/* finger is present! */
|
||||||
fpi_ssm_jump_to_state(ssm, CAPTURE_ACK_00_28);
|
fpi_ssm_jump_to_state(ssm, CAPTURE_ACK_00_28);
|
||||||
break;
|
break;
|
||||||
|
case 0x1e:
|
||||||
|
/* short scan */
|
||||||
|
fp_err("short scan, aborting\n");
|
||||||
|
fpi_imgdev_abort_scan(dev, FP_VERIFY_RETRY_TOO_SHORT);
|
||||||
|
fpi_imgdev_report_finger_status(dev, FALSE);
|
||||||
|
fpi_ssm_jump_to_state(ssm, CAPTURE_ACK_00_28_TERM);
|
||||||
|
break;
|
||||||
|
case 0x1d:
|
||||||
|
/* too much horisontal movement */
|
||||||
|
fp_err("too much horisontal movement, aborting\n");
|
||||||
|
fpi_imgdev_abort_scan(dev, FP_VERIFY_RETRY_CENTER_FINGER);
|
||||||
|
fpi_imgdev_report_finger_status(dev, FALSE);
|
||||||
|
fpi_ssm_jump_to_state(ssm, CAPTURE_ACK_00_28_TERM);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
/* some error happened, cancel scan */
|
/* some error happened, cancel scan */
|
||||||
fp_err("something bad happened, aborting scan :(\n");
|
fp_err("something bad happened, stop scan\n");
|
||||||
fpi_ssm_mark_aborted(ssm, FP_VERIFY_RETRY_REMOVE_FINGER);
|
fpi_imgdev_abort_scan(dev, FP_VERIFY_RETRY);
|
||||||
|
fpi_imgdev_report_finger_status(dev, FALSE);
|
||||||
|
fpi_ssm_jump_to_state(ssm, CAPTURE_ACK_00_28_TERM);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -300,16 +278,17 @@ static void capture_read_data_cb(struct libusb_transfer *transfer)
|
|||||||
upektc_img_process_image_frame(upekdev->image_bits + upekdev->image_size,
|
upektc_img_process_image_frame(upekdev->image_bits + upekdev->image_size,
|
||||||
data);
|
data);
|
||||||
BUG_ON(upekdev->image_size != IMAGE_SIZE);
|
BUG_ON(upekdev->image_size != IMAGE_SIZE);
|
||||||
fp_dbg("Image size is %d\n", upekdev->image_size);
|
fp_dbg("Image size is %lu\n", upekdev->image_size);
|
||||||
img = fpi_img_new(IMAGE_SIZE);
|
img = fpi_img_new(IMAGE_SIZE);
|
||||||
|
img->flags = FP_IMG_PARTIAL;
|
||||||
memcpy(img->data, upekdev->image_bits, IMAGE_SIZE);
|
memcpy(img->data, upekdev->image_bits, IMAGE_SIZE);
|
||||||
fpi_imgdev_image_captured(dev, img);
|
fpi_imgdev_image_captured(dev, img);
|
||||||
fpi_imgdev_report_finger_status(dev, FALSE);
|
fpi_imgdev_report_finger_status(dev, FALSE);
|
||||||
fpi_ssm_mark_completed(ssm);
|
fpi_ssm_mark_completed(ssm);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fp_err("Uknown response!\n");
|
fp_err("Unknown response!\n");
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -318,50 +297,52 @@ static void capture_read_data_cb(struct libusb_transfer *transfer)
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fp_err("Not handled response!\n");
|
fp_err("Not handled response!\n");
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void capture_run_state(struct fpi_ssm *ssm)
|
static void capture_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = user_data;
|
||||||
struct upekts_img_dev *upekdev = dev->priv;
|
struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(_dev);
|
||||||
|
|
||||||
switch (ssm->cur_state) {
|
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||||
case CAPTURE_INIT_CAPTURE:
|
case CAPTURE_INIT_CAPTURE:
|
||||||
upektc_img_submit_req(ssm, upek2020_init_capture, sizeof(upek2020_init_capture),
|
upektc_img_submit_req(ssm, dev, upek2020_init_capture, sizeof(upek2020_init_capture),
|
||||||
upekdev->seq, capture_reqs_cb);
|
upekdev->seq, capture_reqs_cb);
|
||||||
upekdev->seq++;
|
upekdev->seq++;
|
||||||
break;
|
break;
|
||||||
case CAPTURE_READ_DATA:
|
case CAPTURE_READ_DATA:
|
||||||
|
case CAPTURE_READ_DATA_TERM:
|
||||||
if (!upekdev->response_rest)
|
if (!upekdev->response_rest)
|
||||||
upektc_img_read_data(ssm, SHORT_RESPONSE_SIZE, 0, capture_read_data_cb);
|
upektc_img_read_data(ssm, dev, SHORT_RESPONSE_SIZE, 0, capture_read_data_cb);
|
||||||
else
|
else
|
||||||
upektc_img_read_data(ssm, MAX_RESPONSE_SIZE - SHORT_RESPONSE_SIZE,
|
upektc_img_read_data(ssm, dev, MAX_RESPONSE_SIZE - SHORT_RESPONSE_SIZE,
|
||||||
SHORT_RESPONSE_SIZE, capture_read_data_cb);
|
SHORT_RESPONSE_SIZE, capture_read_data_cb);
|
||||||
break;
|
break;
|
||||||
case CAPTURE_ACK_00_28:
|
case CAPTURE_ACK_00_28:
|
||||||
upektc_img_submit_req(ssm, upek2020_ack_00_28, sizeof(upek2020_ack_00_28),
|
case CAPTURE_ACK_00_28_TERM:
|
||||||
|
upektc_img_submit_req(ssm, dev, upek2020_ack_00_28, sizeof(upek2020_ack_00_28),
|
||||||
upekdev->seq, capture_reqs_cb);
|
upekdev->seq, capture_reqs_cb);
|
||||||
upekdev->seq++;
|
upekdev->seq++;
|
||||||
break;
|
break;
|
||||||
case CAPTURE_ACK_08:
|
case CAPTURE_ACK_08:
|
||||||
upektc_img_submit_req(ssm, upek2020_ack_08, sizeof(upek2020_ack_08),
|
upektc_img_submit_req(ssm, dev, upek2020_ack_08, sizeof(upek2020_ack_08),
|
||||||
0, capture_reqs_cb);
|
0, capture_reqs_cb);
|
||||||
break;
|
break;
|
||||||
case CAPTURE_ACK_FRAME:
|
case CAPTURE_ACK_FRAME:
|
||||||
upektc_img_submit_req(ssm, upek2020_ack_frame, sizeof(upek2020_ack_frame),
|
upektc_img_submit_req(ssm, dev, upek2020_ack_frame, sizeof(upek2020_ack_frame),
|
||||||
upekdev->seq, capture_reqs_cb);
|
upekdev->seq, capture_reqs_cb);
|
||||||
upekdev->seq++;
|
upekdev->seq++;
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static void capture_sm_complete(struct fpi_ssm *ssm)
|
static void capture_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = user_data;
|
||||||
struct upekts_img_dev *upekdev = dev->priv;
|
struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(_dev);
|
||||||
int err = ssm->error;
|
int err = fpi_ssm_get_error(ssm);
|
||||||
|
|
||||||
fp_dbg("Capture completed, %d", err);
|
fp_dbg("Capture completed, %d", err);
|
||||||
fpi_ssm_free(ssm);
|
fpi_ssm_free(ssm);
|
||||||
@@ -376,13 +357,12 @@ static void capture_sm_complete(struct fpi_ssm *ssm)
|
|||||||
|
|
||||||
static void start_capture(struct fp_img_dev *dev)
|
static void start_capture(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct upekts_img_dev *upekdev = dev->priv;
|
struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
struct fpi_ssm *ssm;
|
fpi_ssm *ssm;
|
||||||
|
|
||||||
upekdev->image_size = 0;
|
upekdev->image_size = 0;
|
||||||
|
|
||||||
ssm = fpi_ssm_new(dev->dev, capture_run_state, CAPTURE_NUM_STATES);
|
ssm = fpi_ssm_new(FP_DEV(dev), capture_run_state, CAPTURE_NUM_STATES, dev);
|
||||||
ssm->priv = dev;
|
|
||||||
fpi_ssm_start(ssm, capture_sm_complete);
|
fpi_ssm_start(ssm, capture_sm_complete);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -396,50 +376,50 @@ enum deactivate_states {
|
|||||||
|
|
||||||
static void deactivate_reqs_cb(struct libusb_transfer *transfer)
|
static void deactivate_reqs_cb(struct libusb_transfer *transfer)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
|
|
||||||
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
|
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
|
||||||
(transfer->length == transfer->actual_length)) {
|
(transfer->length == transfer->actual_length)) {
|
||||||
fpi_ssm_jump_to_state(ssm, CAPTURE_READ_DATA);
|
fpi_ssm_jump_to_state(ssm, CAPTURE_READ_DATA);
|
||||||
} else {
|
} else {
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: process response properly */
|
/* TODO: process response properly */
|
||||||
static void deactivate_read_data_cb(struct libusb_transfer *transfer)
|
static void deactivate_read_data_cb(struct libusb_transfer *transfer)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
|
|
||||||
if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
|
if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
|
||||||
fpi_ssm_mark_completed(ssm);
|
fpi_ssm_mark_completed(ssm);
|
||||||
} else {
|
} else {
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void deactivate_run_state(struct fpi_ssm *ssm)
|
static void deactivate_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = user_data;
|
||||||
struct upekts_img_dev *upekdev = dev->priv;
|
struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(_dev);
|
||||||
|
|
||||||
switch (ssm->cur_state) {
|
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||||
case DEACTIVATE_DEINIT:
|
case DEACTIVATE_DEINIT:
|
||||||
upektc_img_submit_req(ssm, upek2020_deinit, sizeof(upek2020_deinit),
|
upektc_img_submit_req(ssm, dev, upek2020_deinit, sizeof(upek2020_deinit),
|
||||||
upekdev->seq, deactivate_reqs_cb);
|
upekdev->seq, deactivate_reqs_cb);
|
||||||
upekdev->seq++;
|
upekdev->seq++;
|
||||||
break;
|
break;
|
||||||
case DEACTIVATE_READ_DEINIT_DATA:
|
case DEACTIVATE_READ_DEINIT_DATA:
|
||||||
upektc_img_read_data(ssm, SHORT_RESPONSE_SIZE, 0, deactivate_read_data_cb);
|
upektc_img_read_data(ssm, dev, SHORT_RESPONSE_SIZE, 0, deactivate_read_data_cb);
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static void deactivate_sm_complete(struct fpi_ssm *ssm)
|
static void deactivate_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = user_data;
|
||||||
struct upekts_img_dev *upekdev = dev->priv;
|
struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(_dev);
|
||||||
int err = ssm->error;
|
int err = fpi_ssm_get_error(ssm);
|
||||||
|
|
||||||
fp_dbg("Deactivate completed");
|
fp_dbg("Deactivate completed");
|
||||||
fpi_ssm_free(ssm);
|
fpi_ssm_free(ssm);
|
||||||
@@ -455,13 +435,12 @@ static void deactivate_sm_complete(struct fpi_ssm *ssm)
|
|||||||
|
|
||||||
static void start_deactivation(struct fp_img_dev *dev)
|
static void start_deactivation(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct upekts_img_dev *upekdev = dev->priv;
|
struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
struct fpi_ssm *ssm;
|
fpi_ssm *ssm;
|
||||||
|
|
||||||
upekdev->image_size = 0;
|
upekdev->image_size = 0;
|
||||||
|
|
||||||
ssm = fpi_ssm_new(dev->dev, deactivate_run_state, DEACTIVATE_NUM_STATES);
|
ssm = fpi_ssm_new(FP_DEV(dev), deactivate_run_state, DEACTIVATE_NUM_STATES, dev);
|
||||||
ssm->priv = dev;
|
|
||||||
fpi_ssm_start(ssm, deactivate_sm_complete);
|
fpi_ssm_start(ssm, deactivate_sm_complete);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -483,87 +462,83 @@ enum activate_states {
|
|||||||
|
|
||||||
static void init_reqs_ctrl_cb(struct libusb_transfer *transfer)
|
static void init_reqs_ctrl_cb(struct libusb_transfer *transfer)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
|
|
||||||
if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
|
if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
|
||||||
fpi_ssm_next_state(ssm);
|
fpi_ssm_next_state(ssm);
|
||||||
} else {
|
} else {
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_reqs_cb(struct libusb_transfer *transfer)
|
static void init_reqs_cb(struct libusb_transfer *transfer)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
|
|
||||||
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
|
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) &&
|
||||||
(transfer->length == transfer->actual_length)) {
|
(transfer->length == transfer->actual_length)) {
|
||||||
fpi_ssm_next_state(ssm);
|
fpi_ssm_next_state(ssm);
|
||||||
} else {
|
} else {
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: process response properly */
|
/* TODO: process response properly */
|
||||||
static void init_read_data_cb(struct libusb_transfer *transfer)
|
static void init_read_data_cb(struct libusb_transfer *transfer)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
|
|
||||||
if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
|
if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
|
||||||
fpi_ssm_next_state(ssm);
|
fpi_ssm_next_state(ssm);
|
||||||
} else {
|
} else {
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void activate_run_state(struct fpi_ssm *ssm)
|
static void activate_run_state(fpi_ssm *ssm, struct fp_dev *dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct libusb_transfer *transfer;
|
struct libusb_transfer *transfer;
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *idev = user_data;
|
||||||
struct upekts_img_dev *upekdev = dev->priv;
|
struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(dev);
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
switch (ssm->cur_state) {
|
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||||
case ACTIVATE_CONTROL_REQ_1:
|
case ACTIVATE_CONTROL_REQ_1:
|
||||||
case ACTIVATE_CONTROL_REQ_2:
|
case ACTIVATE_CONTROL_REQ_2:
|
||||||
{
|
{
|
||||||
unsigned char *data;
|
unsigned char *data;
|
||||||
|
|
||||||
transfer = libusb_alloc_transfer(0);
|
transfer = fpi_usb_alloc();
|
||||||
if (!transfer) {
|
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
transfer->flags |= LIBUSB_TRANSFER_FREE_BUFFER |
|
transfer->flags |= LIBUSB_TRANSFER_FREE_BUFFER |
|
||||||
LIBUSB_TRANSFER_FREE_TRANSFER;
|
LIBUSB_TRANSFER_FREE_TRANSFER;
|
||||||
|
|
||||||
data = g_malloc0(LIBUSB_CONTROL_SETUP_SIZE + 1);
|
data = g_malloc0(LIBUSB_CONTROL_SETUP_SIZE + 1);
|
||||||
libusb_fill_control_setup(data,
|
libusb_fill_control_setup(data,
|
||||||
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, 0x0c, 0x100, 0x0400, 1);
|
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, 0x0c, 0x100, 0x0400, 1);
|
||||||
libusb_fill_control_transfer(transfer, ssm->dev->udev, data,
|
libusb_fill_control_transfer(transfer, fpi_dev_get_usb_dev(dev), data,
|
||||||
init_reqs_ctrl_cb, ssm, CTRL_TIMEOUT);
|
init_reqs_ctrl_cb, ssm, CTRL_TIMEOUT);
|
||||||
r = libusb_submit_transfer(transfer);
|
r = libusb_submit_transfer(transfer);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
g_free(data);
|
g_free(data);
|
||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
fpi_ssm_mark_aborted(ssm, r);
|
fpi_ssm_mark_failed(ssm, r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ACTIVATE_INIT_1:
|
case ACTIVATE_INIT_1:
|
||||||
upektc_img_submit_req(ssm, upek2020_init_1, sizeof(upek2020_init_1),
|
upektc_img_submit_req(ssm, idev, upek2020_init_1, sizeof(upek2020_init_1),
|
||||||
0, init_reqs_cb);
|
0, init_reqs_cb);
|
||||||
break;
|
break;
|
||||||
case ACTIVATE_INIT_2:
|
case ACTIVATE_INIT_2:
|
||||||
upektc_img_submit_req(ssm, upek2020_init_2, sizeof(upek2020_init_2),
|
upektc_img_submit_req(ssm, idev, upek2020_init_2, sizeof(upek2020_init_2),
|
||||||
0, init_reqs_cb);
|
0, init_reqs_cb);
|
||||||
break;
|
break;
|
||||||
case ACTIVATE_INIT_3:
|
case ACTIVATE_INIT_3:
|
||||||
upektc_img_submit_req(ssm, upek2020_init_3, sizeof(upek2020_init_3),
|
upektc_img_submit_req(ssm, idev, upek2020_init_3, sizeof(upek2020_init_3),
|
||||||
0, init_reqs_cb);
|
0, init_reqs_cb);
|
||||||
break;
|
break;
|
||||||
case ACTIVATE_INIT_4:
|
case ACTIVATE_INIT_4:
|
||||||
upektc_img_submit_req(ssm, upek2020_init_4, sizeof(upek2020_init_4),
|
upektc_img_submit_req(ssm, idev, upek2020_init_4, sizeof(upek2020_init_4),
|
||||||
upekdev->seq, init_reqs_cb);
|
upekdev->seq, init_reqs_cb);
|
||||||
/* Seq should be updated after 4th init */
|
/* Seq should be updated after 4th init */
|
||||||
upekdev->seq++;
|
upekdev->seq++;
|
||||||
@@ -574,15 +549,15 @@ static void activate_run_state(struct fpi_ssm *ssm)
|
|||||||
case ACTIVATE_READ_INIT_2_RESP:
|
case ACTIVATE_READ_INIT_2_RESP:
|
||||||
case ACTIVATE_READ_INIT_3_RESP:
|
case ACTIVATE_READ_INIT_3_RESP:
|
||||||
case ACTIVATE_READ_INIT_4_RESP:
|
case ACTIVATE_READ_INIT_4_RESP:
|
||||||
upektc_img_read_data(ssm, SHORT_RESPONSE_SIZE, 0, init_read_data_cb);
|
upektc_img_read_data(ssm, idev, SHORT_RESPONSE_SIZE, 0, init_read_data_cb);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void activate_sm_complete(struct fpi_ssm *ssm)
|
static void activate_sm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = user_data;
|
||||||
int err = ssm->error;
|
int err = fpi_ssm_get_error(ssm);
|
||||||
|
|
||||||
fpi_ssm_free(ssm);
|
fpi_ssm_free(ssm);
|
||||||
fp_dbg("%s status %d", __func__, err);
|
fp_dbg("%s status %d", __func__, err);
|
||||||
@@ -592,12 +567,11 @@ static void activate_sm_complete(struct fpi_ssm *ssm)
|
|||||||
start_capture(dev);
|
start_capture(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
static int dev_activate(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct upekts_img_dev *upekdev = dev->priv;
|
struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
struct fpi_ssm *ssm = fpi_ssm_new(dev->dev, activate_run_state,
|
fpi_ssm *ssm = fpi_ssm_new(FP_DEV(dev), activate_run_state,
|
||||||
ACTIVATE_NUM_STATES);
|
ACTIVATE_NUM_STATES, dev);
|
||||||
ssm->priv = dev;
|
|
||||||
upekdev->seq = 0;
|
upekdev->seq = 0;
|
||||||
fpi_ssm_start(ssm, activate_sm_complete);
|
fpi_ssm_start(ssm, activate_sm_complete);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -605,7 +579,7 @@ static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
|||||||
|
|
||||||
static void dev_deactivate(struct fp_img_dev *dev)
|
static void dev_deactivate(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct upekts_img_dev *upekdev = dev->priv;
|
struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
|
||||||
upekdev->deactivating = TRUE;
|
upekdev->deactivating = TRUE;
|
||||||
}
|
}
|
||||||
@@ -614,22 +588,25 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
|||||||
{
|
{
|
||||||
/* TODO check that device has endpoints we're using */
|
/* TODO check that device has endpoints we're using */
|
||||||
int r;
|
int r;
|
||||||
|
struct upektc_img_dev *upekdev;
|
||||||
|
|
||||||
r = libusb_claim_interface(dev->udev, 0);
|
r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
fp_err("could not claim interface 0");
|
fp_err("could not claim interface 0: %s", libusb_error_name(r));
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev->priv = g_malloc0(sizeof(struct upekts_img_dev));
|
upekdev = g_malloc0(sizeof(struct upektc_img_dev));
|
||||||
|
fp_dev_set_instance_data(FP_DEV(dev), upekdev);
|
||||||
fpi_imgdev_open_complete(dev, 0);
|
fpi_imgdev_open_complete(dev, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dev_deinit(struct fp_img_dev *dev)
|
static void dev_deinit(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
g_free(dev->priv);
|
struct upektc_img_dev *upekdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
libusb_release_interface(dev->udev, 0);
|
g_free(upekdev);
|
||||||
|
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||||
fpi_imgdev_close_complete(dev);
|
fpi_imgdev_close_complete(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -637,18 +614,14 @@ static int discover(struct libusb_device_descriptor *dsc, uint32_t *devtype)
|
|||||||
{
|
{
|
||||||
if (dsc->idProduct == 0x2020 && dsc->bcdDevice == 1)
|
if (dsc->idProduct == 0x2020 && dsc->bcdDevice == 1)
|
||||||
return 1;
|
return 1;
|
||||||
#ifndef ENABLE_UPEKE2
|
|
||||||
if (dsc->idProduct == 0x2016 && dsc->bcdDevice == 2)
|
if (dsc->idProduct == 0x2016 && dsc->bcdDevice == 2)
|
||||||
return 1;
|
return 1;
|
||||||
#endif
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct usb_id id_table[] = {
|
static const struct usb_id id_table[] = {
|
||||||
#ifndef ENABLE_UPEKE2
|
|
||||||
{ .vendor = 0x147e, .product = 0x2016 },
|
{ .vendor = 0x147e, .product = 0x2016 },
|
||||||
#endif
|
|
||||||
{ .vendor = 0x147e, .product = 0x2020 },
|
{ .vendor = 0x147e, .product = 0x2020 },
|
||||||
{ 0, 0, 0, },
|
{ 0, 0, 0, },
|
||||||
};
|
};
|
||||||
@@ -665,7 +638,7 @@ struct fp_img_driver upektc_img_driver = {
|
|||||||
.flags = 0,
|
.flags = 0,
|
||||||
.img_height = IMAGE_HEIGHT,
|
.img_height = IMAGE_HEIGHT,
|
||||||
.img_width = IMAGE_WIDTH,
|
.img_width = IMAGE_WIDTH,
|
||||||
.bz3_threshold = 70,
|
.bz3_threshold = 20,
|
||||||
|
|
||||||
.open = dev_init,
|
.open = dev_init,
|
||||||
.close = dev_deinit,
|
.close = dev_deinit,
|
||||||
|
|||||||
@@ -27,15 +27,9 @@
|
|||||||
|
|
||||||
#define FP_COMPONENT "upekts"
|
#define FP_COMPONENT "upekts"
|
||||||
|
|
||||||
#include <errno.h>
|
#include "drivers_api.h"
|
||||||
#include <string.h>
|
#include "fpi-async.h"
|
||||||
|
#include "upek_proto.h"
|
||||||
#include <glib.h>
|
|
||||||
#include <libusb.h>
|
|
||||||
|
|
||||||
#include <fp_internal.h>
|
|
||||||
|
|
||||||
#include "driver_ids.h"
|
|
||||||
|
|
||||||
#define EP_IN (1 | LIBUSB_ENDPOINT_IN)
|
#define EP_IN (1 | LIBUSB_ENDPOINT_IN)
|
||||||
#define EP_OUT (2 | LIBUSB_ENDPOINT_OUT)
|
#define EP_OUT (2 | LIBUSB_ENDPOINT_OUT)
|
||||||
@@ -51,49 +45,7 @@ struct upekts_dev {
|
|||||||
uint8_t seq; /* FIXME: improve/automate seq handling */
|
uint8_t seq; /* FIXME: improve/automate seq handling */
|
||||||
};
|
};
|
||||||
|
|
||||||
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
|
|
||||||
};
|
|
||||||
|
|
||||||
static 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* MESSAGE FORMAT
|
* MESSAGE FORMAT
|
||||||
@@ -139,17 +91,15 @@ static struct libusb_transfer *alloc_send_cmd_transfer(struct fp_dev *dev,
|
|||||||
unsigned char seq_a, unsigned char seq_b, const unsigned char *data,
|
unsigned char seq_a, unsigned char seq_b, const unsigned char *data,
|
||||||
uint16_t len, libusb_transfer_cb_fn callback, void *user_data)
|
uint16_t len, libusb_transfer_cb_fn callback, void *user_data)
|
||||||
{
|
{
|
||||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||||
uint16_t crc;
|
uint16_t crc;
|
||||||
|
const char *ciao = "Ciao";
|
||||||
|
|
||||||
/* 9 bytes extra for: 4 byte 'Ciao', 1 byte A, 1 byte B | lenHI,
|
/* 9 bytes extra for: 4 byte 'Ciao', 1 byte A, 1 byte B | lenHI,
|
||||||
* 1 byte lenLO, 2 byte CRC */
|
* 1 byte lenLO, 2 byte CRC */
|
||||||
size_t urblen = len + 9;
|
size_t urblen = len + 9;
|
||||||
unsigned char *buf;
|
unsigned char *buf;
|
||||||
|
|
||||||
if (!transfer)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (!data && len > 0) {
|
if (!data && len > 0) {
|
||||||
fp_err("len>0 but no data?");
|
fp_err("len>0 but no data?");
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -158,7 +108,7 @@ static struct libusb_transfer *alloc_send_cmd_transfer(struct fp_dev *dev,
|
|||||||
buf = g_malloc(urblen);
|
buf = g_malloc(urblen);
|
||||||
|
|
||||||
/* Write header */
|
/* Write header */
|
||||||
strncpy(buf, "Ciao", 4);
|
memcpy(buf, ciao, strlen(ciao));
|
||||||
len = GUINT16_TO_LE(len);
|
len = GUINT16_TO_LE(len);
|
||||||
buf[4] = seq_a;
|
buf[4] = seq_a;
|
||||||
buf[5] = seq_b | ((len & 0xf00) >> 8);
|
buf[5] = seq_b | ((len & 0xf00) >> 8);
|
||||||
@@ -173,7 +123,7 @@ static struct libusb_transfer *alloc_send_cmd_transfer(struct fp_dev *dev,
|
|||||||
buf[urblen - 2] = crc >> 8;
|
buf[urblen - 2] = crc >> 8;
|
||||||
buf[urblen - 1] = crc & 0xff;
|
buf[urblen - 1] = crc & 0xff;
|
||||||
|
|
||||||
libusb_fill_bulk_transfer(transfer, dev->udev, EP_OUT, buf, urblen,
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(dev), EP_OUT, buf, urblen,
|
||||||
callback, user_data, TIMEOUT);
|
callback, user_data, TIMEOUT);
|
||||||
return transfer;
|
return transfer;
|
||||||
}
|
}
|
||||||
@@ -185,7 +135,7 @@ static struct libusb_transfer *alloc_send_cmd28_transfer(struct fp_dev *dev,
|
|||||||
uint16_t _innerlen = innerlen;
|
uint16_t _innerlen = innerlen;
|
||||||
size_t len = innerlen + 6;
|
size_t len = innerlen + 6;
|
||||||
unsigned char *buf = g_malloc0(len);
|
unsigned char *buf = g_malloc0(len);
|
||||||
struct upekts_dev *upekdev = dev->priv;
|
struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev);
|
||||||
uint8_t seq = upekdev->seq + CMD_SEQ_INCREMENT;
|
uint8_t seq = upekdev->seq + CMD_SEQ_INCREMENT;
|
||||||
struct libusb_transfer *ret;
|
struct libusb_transfer *ret;
|
||||||
|
|
||||||
@@ -415,16 +365,13 @@ static void read_msg_cb(struct libusb_transfer *transfer)
|
|||||||
* to read the remainder. This is handled below. */
|
* to read the remainder. This is handled below. */
|
||||||
if (len > MAX_DATA_IN_READ_BUF) {
|
if (len > MAX_DATA_IN_READ_BUF) {
|
||||||
int needed = len - MAX_DATA_IN_READ_BUF;
|
int needed = len - MAX_DATA_IN_READ_BUF;
|
||||||
struct libusb_transfer *etransfer = libusb_alloc_transfer(0);
|
struct libusb_transfer *etransfer = fpi_usb_alloc();
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (!transfer)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
fp_dbg("didn't fit in buffer, need to extend by %d bytes", needed);
|
fp_dbg("didn't fit in buffer, need to extend by %d bytes", needed);
|
||||||
data = g_realloc((gpointer) data, MSG_READ_BUF_SIZE + needed);
|
data = g_realloc((gpointer) data, MSG_READ_BUF_SIZE + needed);
|
||||||
|
|
||||||
libusb_fill_bulk_transfer(etransfer, udata->dev->udev, EP_IN,
|
libusb_fill_bulk_transfer(etransfer, fpi_dev_get_usb_dev(udata->dev), EP_IN,
|
||||||
data + MSG_READ_BUF_SIZE, needed, read_msg_extend_cb, udata,
|
data + MSG_READ_BUF_SIZE, needed, read_msg_extend_cb, udata,
|
||||||
TIMEOUT);
|
TIMEOUT);
|
||||||
|
|
||||||
@@ -455,15 +402,10 @@ out:
|
|||||||
static int __read_msg_async(struct read_msg_data *udata)
|
static int __read_msg_async(struct read_msg_data *udata)
|
||||||
{
|
{
|
||||||
unsigned char *buf = g_malloc(MSG_READ_BUF_SIZE);
|
unsigned char *buf = g_malloc(MSG_READ_BUF_SIZE);
|
||||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (!transfer) {
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(udata->dev), EP_IN, buf,
|
||||||
g_free(buf);
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
libusb_fill_bulk_transfer(transfer, udata->dev->udev, EP_IN, buf,
|
|
||||||
MSG_READ_BUF_SIZE, read_msg_cb, udata, TIMEOUT);
|
MSG_READ_BUF_SIZE, read_msg_cb, udata, TIMEOUT);
|
||||||
r = libusb_submit_transfer(transfer);
|
r = libusb_submit_transfer(transfer);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
@@ -532,27 +474,30 @@ enum initsm_states {
|
|||||||
INITSM_NUM_STATES,
|
INITSM_NUM_STATES,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void initsm_read_msg_response_cb(struct fpi_ssm *ssm,
|
static void
|
||||||
enum read_msg_status status, uint8_t seq,
|
initsm_read_msg_response_cb(fpi_ssm *ssm,
|
||||||
unsigned char expect_subcmd, unsigned char subcmd)
|
struct fp_dev *dev,
|
||||||
|
enum read_msg_status status,
|
||||||
|
uint8_t seq,
|
||||||
|
unsigned char expect_subcmd,
|
||||||
|
unsigned char subcmd)
|
||||||
{
|
{
|
||||||
struct fp_dev *dev = ssm->dev;
|
struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev);
|
||||||
struct upekts_dev *upekdev = dev->priv;
|
|
||||||
|
|
||||||
if (status != READ_MSG_RESPONSE) {
|
if (status != READ_MSG_RESPONSE) {
|
||||||
fp_err("expected response, got %d seq=%x in state %d", status, seq,
|
fp_err("expected response, got %d seq=%x in state %d", status, seq,
|
||||||
ssm->cur_state);
|
fpi_ssm_get_cur_state(ssm));
|
||||||
fpi_ssm_mark_aborted(ssm, -1);
|
fpi_ssm_mark_failed(ssm, -1);
|
||||||
} else if (subcmd != expect_subcmd) {
|
} else if (subcmd != expect_subcmd) {
|
||||||
fp_warn("expected response to subcmd 0x%02x, got response to %02x in "
|
fp_warn("expected response to subcmd 0x%02x, got response to %02x in "
|
||||||
"state %d", expect_subcmd, subcmd, ssm->cur_state);
|
"state %d", expect_subcmd, subcmd, fpi_ssm_get_cur_state(ssm));
|
||||||
fpi_ssm_mark_aborted(ssm, -1);
|
fpi_ssm_mark_failed(ssm, -1);
|
||||||
} else if (seq != upekdev->seq) {
|
} else if (seq != upekdev->seq) {
|
||||||
fp_err("expected response to cmd seq=%02x, got response to %02x "
|
fp_err("expected response to cmd seq=%02x, got response to %02x "
|
||||||
"in state %d", upekdev->seq, seq, ssm->cur_state);
|
"in state %d", upekdev->seq, seq, fpi_ssm_get_cur_state(ssm));
|
||||||
fpi_ssm_mark_aborted(ssm, -1);
|
fpi_ssm_mark_failed(ssm, -1);
|
||||||
} else {
|
} else {
|
||||||
fp_dbg("state %d completed", ssm->cur_state);
|
fp_dbg("state %d completed", fpi_ssm_get_cur_state(ssm));
|
||||||
fpi_ssm_next_state(ssm);
|
fpi_ssm_next_state(ssm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -561,7 +506,7 @@ static void read28_0b_cb(struct fp_dev *dev, enum read_msg_status status,
|
|||||||
uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len,
|
uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
initsm_read_msg_response_cb((struct fpi_ssm *) user_data, status, seq,
|
initsm_read_msg_response_cb((fpi_ssm *) user_data, dev, status, seq,
|
||||||
0x0b, subcmd);
|
0x0b, subcmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -569,7 +514,7 @@ static void read28_0c_cb(struct fp_dev *dev, enum read_msg_status status,
|
|||||||
uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len,
|
uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
initsm_read_msg_response_cb((struct fpi_ssm *) user_data, status, seq,
|
initsm_read_msg_response_cb((fpi_ssm *) user_data, dev, status, seq,
|
||||||
0x0c, subcmd);
|
0x0c, subcmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -577,7 +522,7 @@ static void read28_08_cb(struct fp_dev *dev, enum read_msg_status status,
|
|||||||
uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len,
|
uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
initsm_read_msg_response_cb((struct fpi_ssm *) user_data, status, seq,
|
initsm_read_msg_response_cb((fpi_ssm *) user_data, dev, status, seq,
|
||||||
0x08, subcmd);
|
0x08, subcmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -585,7 +530,7 @@ static void read28_07_cb(struct fp_dev *dev, enum read_msg_status status,
|
|||||||
uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len,
|
uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
initsm_read_msg_response_cb((struct fpi_ssm *) user_data, status, seq,
|
initsm_read_msg_response_cb((fpi_ssm *) user_data, dev, status, seq,
|
||||||
0x07, subcmd);
|
0x07, subcmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -593,30 +538,33 @@ static void read28_06_cb(struct fp_dev *dev, enum read_msg_status status,
|
|||||||
uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len,
|
uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
initsm_read_msg_response_cb((struct fpi_ssm *) user_data, status, seq,
|
initsm_read_msg_response_cb((fpi_ssm *) user_data, dev, status, seq,
|
||||||
0x06, subcmd);
|
0x06, subcmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void initsm_read_msg_cmd_cb(struct fpi_ssm *ssm,
|
static void
|
||||||
enum read_msg_status status, uint8_t expect_seq, uint8_t seq)
|
initsm_read_msg_cmd_cb(fpi_ssm *ssm,
|
||||||
|
struct fp_dev *dev,
|
||||||
|
enum read_msg_status status,
|
||||||
|
uint8_t expect_seq,
|
||||||
|
uint8_t seq)
|
||||||
{
|
{
|
||||||
struct fp_dev *dev = ssm->dev;
|
struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev);
|
||||||
struct upekts_dev *upekdev = dev->priv;
|
|
||||||
|
|
||||||
if (status == READ_MSG_ERROR) {
|
if (status == READ_MSG_ERROR) {
|
||||||
fpi_ssm_mark_aborted(ssm, -1);
|
fpi_ssm_mark_failed(ssm, -1);
|
||||||
return;
|
return;
|
||||||
} else if (status != READ_MSG_CMD) {
|
} else if (status != READ_MSG_CMD) {
|
||||||
fp_err("expected command, got %d seq=%x in state %d", status, seq,
|
fp_err("expected command, got %d seq=%x in state %d", status, seq,
|
||||||
ssm->cur_state);
|
fpi_ssm_get_cur_state(ssm));
|
||||||
fpi_ssm_mark_aborted(ssm, -1);
|
fpi_ssm_mark_failed(ssm, -1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
upekdev->seq = seq;
|
upekdev->seq = seq;
|
||||||
if (seq != expect_seq) {
|
if (seq != expect_seq) {
|
||||||
fp_err("expected seq=%x, got %x in state %d", expect_seq, seq,
|
fp_err("expected seq=%x, got %x in state %d", expect_seq, seq,
|
||||||
ssm->cur_state);
|
fpi_ssm_get_cur_state(ssm));
|
||||||
fpi_ssm_mark_aborted(ssm, -1);
|
fpi_ssm_mark_failed(ssm, -1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -627,114 +575,113 @@ static void read_msg05_cb(struct fp_dev *dev, enum read_msg_status status,
|
|||||||
uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len,
|
uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
initsm_read_msg_cmd_cb((struct fpi_ssm *) user_data, status, 5, seq);
|
initsm_read_msg_cmd_cb((fpi_ssm *) user_data, dev, status, 5, seq);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void read_msg03_cb(struct fp_dev *dev, enum read_msg_status status,
|
static void read_msg03_cb(struct fp_dev *dev, enum read_msg_status status,
|
||||||
uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len,
|
uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
initsm_read_msg_cmd_cb((struct fpi_ssm *) user_data, status, 3, seq);
|
initsm_read_msg_cmd_cb((fpi_ssm *) user_data, dev, status, 3, seq);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ctrl400_cb(struct libusb_transfer *transfer)
|
static void ctrl400_cb(struct libusb_transfer *transfer)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
/* FIXME check length? */
|
/* FIXME check length? */
|
||||||
if (transfer->status == LIBUSB_TRANSFER_COMPLETED)
|
if (transfer->status == LIBUSB_TRANSFER_COMPLETED)
|
||||||
fpi_ssm_next_state(ssm);
|
fpi_ssm_next_state(ssm);
|
||||||
else
|
else
|
||||||
fpi_ssm_mark_aborted(ssm, -1);
|
fpi_ssm_mark_failed(ssm, -1);
|
||||||
g_free(transfer->buffer);
|
g_free(transfer->buffer);
|
||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void initsm_read_msg_handler(struct fpi_ssm *ssm,
|
static void
|
||||||
read_msg_cb_fn callback)
|
initsm_read_msg_handler(fpi_ssm *ssm,
|
||||||
|
struct fp_dev *dev,
|
||||||
|
read_msg_cb_fn callback)
|
||||||
{
|
{
|
||||||
int r = read_msg_async(ssm->dev, callback, ssm);
|
int r = read_msg_async(dev, callback, ssm);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
fp_err("async read msg failed in state %d", ssm->cur_state);
|
fp_err("async read msg failed in state %d", fpi_ssm_get_cur_state(ssm));
|
||||||
fpi_ssm_mark_aborted(ssm, r);
|
fpi_ssm_mark_failed(ssm, r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void initsm_send_msg_cb(struct libusb_transfer *transfer)
|
static void initsm_send_msg_cb(struct libusb_transfer *transfer)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
if (transfer->status == LIBUSB_TRANSFER_COMPLETED
|
if (transfer->status == LIBUSB_TRANSFER_COMPLETED
|
||||||
&& transfer->length == transfer->actual_length) {
|
&& transfer->length == transfer->actual_length) {
|
||||||
fp_dbg("state %d completed", ssm->cur_state);
|
fp_dbg("state %d completed", fpi_ssm_get_cur_state(ssm));
|
||||||
fpi_ssm_next_state(ssm);
|
fpi_ssm_next_state(ssm);
|
||||||
} else {
|
} else {
|
||||||
fp_err("failed, state=%d rqlength=%d actual_length=%d", ssm->cur_state,
|
fp_err("failed, state=%d rqlength=%d actual_length=%d", fpi_ssm_get_cur_state(ssm),
|
||||||
transfer->length, transfer->actual_length);
|
transfer->length, transfer->actual_length);
|
||||||
fpi_ssm_mark_aborted(ssm, -1);
|
fpi_ssm_mark_failed(ssm, -1);
|
||||||
}
|
}
|
||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void initsm_send_msg28_handler(struct fpi_ssm *ssm,
|
static void
|
||||||
unsigned char subcmd, const unsigned char *data, uint16_t innerlen)
|
initsm_send_msg28_handler(fpi_ssm *ssm,
|
||||||
|
struct fp_dev *dev,
|
||||||
|
unsigned char subcmd,
|
||||||
|
const unsigned char *data,
|
||||||
|
uint16_t innerlen)
|
||||||
{
|
{
|
||||||
struct fp_dev *dev = ssm->dev;
|
|
||||||
struct libusb_transfer *transfer;
|
struct libusb_transfer *transfer;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
transfer = alloc_send_cmd28_transfer(dev, subcmd, data, innerlen,
|
transfer = alloc_send_cmd28_transfer(dev, subcmd, data, innerlen,
|
||||||
initsm_send_msg_cb, ssm);
|
initsm_send_msg_cb, ssm);
|
||||||
if (!transfer) {
|
if (!transfer) {
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
fpi_ssm_mark_failed(ssm, -ENOMEM);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = libusb_submit_transfer(transfer);
|
r = libusb_submit_transfer(transfer);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
fp_err("urb submission failed error %d in state %d", r, ssm->cur_state);
|
fp_err("urb submission failed error %d in state %d", r, fpi_ssm_get_cur_state(ssm));
|
||||||
g_free(transfer->buffer);
|
g_free(transfer->buffer);
|
||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void initsm_run_state(struct fpi_ssm *ssm)
|
static void initsm_run_state(fpi_ssm *ssm, struct fp_dev *dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_dev *dev = ssm->dev;
|
struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev);
|
||||||
struct upekts_dev *upekdev = dev->priv;
|
|
||||||
struct libusb_transfer *transfer;
|
struct libusb_transfer *transfer;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
switch (ssm->cur_state) {
|
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||||
case WRITE_CTRL400: ;
|
case WRITE_CTRL400: ;
|
||||||
unsigned char *data;
|
unsigned char *data;
|
||||||
|
|
||||||
transfer = libusb_alloc_transfer(0);
|
transfer = fpi_usb_alloc();
|
||||||
if (!transfer) {
|
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE + 1);
|
data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE + 1);
|
||||||
libusb_fill_control_setup(data,
|
libusb_fill_control_setup(data,
|
||||||
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, 0x0c, 0x100, 0x0400, 1);
|
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, 0x0c, 0x100, 0x0400, 1);
|
||||||
libusb_fill_control_transfer(transfer, ssm->dev->udev, data,
|
libusb_fill_control_transfer(transfer, fpi_dev_get_usb_dev(dev), data,
|
||||||
ctrl400_cb, ssm, TIMEOUT);
|
ctrl400_cb, ssm, TIMEOUT);
|
||||||
|
|
||||||
r = libusb_submit_transfer(transfer);
|
r = libusb_submit_transfer(transfer);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
g_free(data);
|
g_free(data);
|
||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
fpi_ssm_mark_aborted(ssm, r);
|
fpi_ssm_mark_failed(ssm, r);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case READ_MSG03:
|
case READ_MSG03:
|
||||||
initsm_read_msg_handler(ssm, read_msg03_cb);
|
initsm_read_msg_handler(ssm, dev, read_msg03_cb);
|
||||||
break;
|
break;
|
||||||
case SEND_RESP03: ;
|
case SEND_RESP03: ;
|
||||||
transfer = alloc_send_cmdresponse_transfer(dev, ++upekdev->seq,
|
transfer = alloc_send_cmdresponse_transfer(dev, ++upekdev->seq,
|
||||||
init_resp03, sizeof(init_resp03), initsm_send_msg_cb, ssm);
|
init_resp03, sizeof(init_resp03), initsm_send_msg_cb, ssm);
|
||||||
if (!transfer) {
|
if (!transfer) {
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
fpi_ssm_mark_failed(ssm, -ENOMEM);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -742,51 +689,52 @@ static void initsm_run_state(struct fpi_ssm *ssm)
|
|||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
g_free(transfer->buffer);
|
g_free(transfer->buffer);
|
||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
fpi_ssm_mark_aborted(ssm, r);
|
fpi_ssm_mark_failed(ssm, r);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case READ_MSG05:
|
case READ_MSG05:
|
||||||
initsm_read_msg_handler(ssm, read_msg05_cb);
|
initsm_read_msg_handler(ssm, dev, read_msg05_cb);
|
||||||
break;
|
break;
|
||||||
case SEND28_06: ;
|
case SEND28_06: ;
|
||||||
unsigned char dummy28_06 = 0x04;
|
unsigned char dummy28_06 = 0x04;
|
||||||
upekdev->seq = 0xf0;
|
upekdev->seq = 0xf0;
|
||||||
initsm_send_msg28_handler(ssm, 0x06, &dummy28_06, 1);
|
initsm_send_msg28_handler(ssm, dev, 0x06, &dummy28_06, 1);
|
||||||
break;
|
break;
|
||||||
case READ28_06:
|
case READ28_06:
|
||||||
initsm_read_msg_handler(ssm, read28_06_cb);
|
initsm_read_msg_handler(ssm, dev, read28_06_cb);
|
||||||
break;
|
break;
|
||||||
case SEND28_07: ;
|
case SEND28_07: ;
|
||||||
unsigned char dummy28_07 = 0x04;
|
unsigned char dummy28_07 = 0x04;
|
||||||
initsm_send_msg28_handler(ssm, 0x07, &dummy28_07, 1);
|
initsm_send_msg28_handler(ssm, dev, 0x07, &dummy28_07, 1);
|
||||||
break;
|
break;
|
||||||
case READ28_07:
|
case READ28_07:
|
||||||
initsm_read_msg_handler(ssm, read28_07_cb);
|
initsm_read_msg_handler(ssm, dev, read28_07_cb);
|
||||||
break;
|
break;
|
||||||
case SEND28_08:
|
case SEND28_08:
|
||||||
initsm_send_msg28_handler(ssm, 0x08, init28_08, sizeof(init28_08));
|
initsm_send_msg28_handler(ssm, dev, 0x08, init28_08, sizeof(init28_08));
|
||||||
break;
|
break;
|
||||||
case READ28_08:
|
case READ28_08:
|
||||||
initsm_read_msg_handler(ssm, read28_08_cb);
|
initsm_read_msg_handler(ssm, dev, read28_08_cb);
|
||||||
break;
|
break;
|
||||||
case SEND28_0C:
|
case SEND28_0C:
|
||||||
initsm_send_msg28_handler(ssm, 0x0c, init28_0c, sizeof(init28_0c));
|
initsm_send_msg28_handler(ssm, dev, 0x0c, init28_0c, sizeof(init28_0c));
|
||||||
break;
|
break;
|
||||||
case READ28_0C:
|
case READ28_0C:
|
||||||
initsm_read_msg_handler(ssm, read28_0c_cb);
|
initsm_read_msg_handler(ssm, dev, read28_0c_cb);
|
||||||
break;
|
break;
|
||||||
case SEND28_0B:
|
case SEND28_0B:
|
||||||
initsm_send_msg28_handler(ssm, 0x0b, init28_0b, sizeof(init28_0b));
|
initsm_send_msg28_handler(ssm, dev, 0x0b, init28_0b, sizeof(init28_0b));
|
||||||
break;
|
break;
|
||||||
case READ28_0B:
|
case READ28_0B:
|
||||||
initsm_read_msg_handler(ssm, read28_0b_cb);
|
initsm_read_msg_handler(ssm, dev, read28_0b_cb);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct fpi_ssm *initsm_new(struct fp_dev *dev)
|
static fpi_ssm *initsm_new(struct fp_dev *dev,
|
||||||
|
void *user_data)
|
||||||
{
|
{
|
||||||
return fpi_ssm_new(dev, initsm_run_state, INITSM_NUM_STATES);
|
return fpi_ssm_new(dev, initsm_run_state, INITSM_NUM_STATES, user_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum deinitsm_states {
|
enum deinitsm_states {
|
||||||
@@ -797,11 +745,11 @@ enum deinitsm_states {
|
|||||||
|
|
||||||
static void send_resp07_cb(struct libusb_transfer *transfer)
|
static void send_resp07_cb(struct libusb_transfer *transfer)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
|
if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
else if (transfer->length != transfer->actual_length)
|
else if (transfer->length != transfer->actual_length)
|
||||||
fpi_ssm_mark_aborted(ssm, -EPROTO);
|
fpi_ssm_mark_failed(ssm, -EPROTO);
|
||||||
else
|
else
|
||||||
fpi_ssm_next_state(ssm);
|
fpi_ssm_next_state(ssm);
|
||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
@@ -811,33 +759,32 @@ static void read_msg01_cb(struct fp_dev *dev, enum read_msg_status status,
|
|||||||
uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len,
|
uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = user_data;
|
fpi_ssm *ssm = user_data;
|
||||||
struct upekts_dev *upekdev = dev->priv;
|
struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev);
|
||||||
|
|
||||||
if (status == READ_MSG_ERROR) {
|
if (status == READ_MSG_ERROR) {
|
||||||
fpi_ssm_mark_aborted(ssm, -1);
|
fpi_ssm_mark_failed(ssm, -1);
|
||||||
return;
|
return;
|
||||||
} else if (status != READ_MSG_CMD) {
|
} else if (status != READ_MSG_CMD) {
|
||||||
fp_err("expected command, got %d seq=%x", status, seq);
|
fp_err("expected command, got %d seq=%x", status, seq);
|
||||||
fpi_ssm_mark_aborted(ssm, -1);
|
fpi_ssm_mark_failed(ssm, -1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
upekdev->seq = seq;
|
upekdev->seq = seq;
|
||||||
if (seq != 1) {
|
if (seq != 1) {
|
||||||
fp_err("expected seq=1, got %x", seq);
|
fp_err("expected seq=1, got %x", seq);
|
||||||
fpi_ssm_mark_aborted(ssm, -1);
|
fpi_ssm_mark_failed(ssm, -1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fpi_ssm_next_state(ssm);
|
fpi_ssm_next_state(ssm);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void deinitsm_state_handler(struct fpi_ssm *ssm)
|
static void deinitsm_state_handler(fpi_ssm *ssm, struct fp_dev *dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_dev *dev = ssm->dev;
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
switch (ssm->cur_state) {
|
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||||
case SEND_RESP07: ;
|
case SEND_RESP07: ;
|
||||||
struct libusb_transfer *transfer;
|
struct libusb_transfer *transfer;
|
||||||
unsigned char dummy = 0;
|
unsigned char dummy = 0;
|
||||||
@@ -845,7 +792,7 @@ static void deinitsm_state_handler(struct fpi_ssm *ssm)
|
|||||||
transfer = alloc_send_cmdresponse_transfer(dev, 0x07, &dummy, 1,
|
transfer = alloc_send_cmdresponse_transfer(dev, 0x07, &dummy, 1,
|
||||||
send_resp07_cb, ssm);
|
send_resp07_cb, ssm);
|
||||||
if (!transfer) {
|
if (!transfer) {
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
fpi_ssm_mark_failed(ssm, -ENOMEM);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -853,20 +800,20 @@ static void deinitsm_state_handler(struct fpi_ssm *ssm)
|
|||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
g_free(transfer->buffer);
|
g_free(transfer->buffer);
|
||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
fpi_ssm_mark_aborted(ssm, r);
|
fpi_ssm_mark_failed(ssm, r);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case READ_MSG01: ;
|
case READ_MSG01: ;
|
||||||
r = read_msg_async(dev, read_msg01_cb, ssm);
|
r = read_msg_async(dev, read_msg01_cb, ssm);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
fpi_ssm_mark_aborted(ssm, r);
|
fpi_ssm_mark_failed(ssm, r);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct fpi_ssm *deinitsm_new(struct fp_dev *dev)
|
static fpi_ssm *deinitsm_new(struct fp_dev *dev)
|
||||||
{
|
{
|
||||||
return fpi_ssm_new(dev, deinitsm_state_handler, DEINITSM_NUM_STATES);
|
return fpi_ssm_new(dev, deinitsm_state_handler, DEINITSM_NUM_STATES, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dev_init(struct fp_dev *dev, unsigned long driver_data)
|
static int dev_init(struct fp_dev *dev, unsigned long driver_data)
|
||||||
@@ -874,14 +821,16 @@ static int dev_init(struct fp_dev *dev, unsigned long driver_data)
|
|||||||
struct upekts_dev *upekdev = NULL;
|
struct upekts_dev *upekdev = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
r = libusb_claim_interface(dev->udev, 0);
|
r = libusb_claim_interface(fpi_dev_get_usb_dev(dev), 0);
|
||||||
if (r < 0)
|
if (r < 0) {
|
||||||
|
fp_err("could not claim interface 0: %s", libusb_error_name(r));
|
||||||
return r;
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
upekdev = g_malloc(sizeof(*upekdev));
|
upekdev = g_malloc(sizeof(*upekdev));
|
||||||
upekdev->seq = 0xf0; /* incremented to 0x00 before first cmd */
|
upekdev->seq = 0xf0; /* incremented to 0x00 before first cmd */
|
||||||
dev->priv = upekdev;
|
fp_dev_set_instance_data(dev, upekdev);
|
||||||
dev->nr_enroll_stages = 3;
|
fpi_dev_set_nr_enroll_stages(dev, 3);
|
||||||
|
|
||||||
fpi_drvcb_open_complete(dev, 0);
|
fpi_drvcb_open_complete(dev, 0);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -889,8 +838,10 @@ static int dev_init(struct fp_dev *dev, unsigned long driver_data)
|
|||||||
|
|
||||||
static void dev_exit(struct fp_dev *dev)
|
static void dev_exit(struct fp_dev *dev)
|
||||||
{
|
{
|
||||||
libusb_release_interface(dev->udev, 0);
|
struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev);
|
||||||
g_free(dev->priv);
|
|
||||||
|
libusb_release_interface(fpi_dev_get_usb_dev(dev), 0);
|
||||||
|
g_free(upekdev);
|
||||||
fpi_drvcb_close_complete(dev);
|
fpi_drvcb_close_complete(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -912,14 +863,14 @@ enum enroll_start_sm_states {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* Called when the device initialization state machine completes */
|
/* Called when the device initialization state machine completes */
|
||||||
static void enroll_start_sm_cb_initsm(struct fpi_ssm *initsm)
|
static void enroll_start_sm_cb_initsm(fpi_ssm *initsm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *enroll_start_ssm = initsm->priv;
|
fpi_ssm *enroll_start_ssm = user_data;
|
||||||
int error = initsm->error;
|
int error = fpi_ssm_get_error(initsm);
|
||||||
|
|
||||||
fpi_ssm_free(initsm);
|
fpi_ssm_free(initsm);
|
||||||
if (error)
|
if (error)
|
||||||
fpi_ssm_mark_aborted(enroll_start_ssm, error);
|
fpi_ssm_mark_failed(enroll_start_ssm, error);
|
||||||
else
|
else
|
||||||
fpi_ssm_next_state(enroll_start_ssm);
|
fpi_ssm_next_state(enroll_start_ssm);
|
||||||
}
|
}
|
||||||
@@ -927,11 +878,11 @@ static void enroll_start_sm_cb_initsm(struct fpi_ssm *initsm)
|
|||||||
/* called when enroll init URB has completed */
|
/* called when enroll init URB has completed */
|
||||||
static void enroll_start_sm_cb_init(struct libusb_transfer *transfer)
|
static void enroll_start_sm_cb_init(struct libusb_transfer *transfer)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
|
if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
else if (transfer->length != transfer->actual_length)
|
else if (transfer->length != transfer->actual_length)
|
||||||
fpi_ssm_mark_aborted(ssm, -EPROTO);
|
fpi_ssm_mark_failed(ssm, -EPROTO);
|
||||||
else
|
else
|
||||||
fpi_ssm_next_state(ssm);
|
fpi_ssm_next_state(ssm);
|
||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
@@ -941,34 +892,32 @@ static void enroll_start_sm_cb_msg28(struct fp_dev *dev,
|
|||||||
enum read_msg_status status, uint8_t seq, unsigned char subcmd,
|
enum read_msg_status status, uint8_t seq, unsigned char subcmd,
|
||||||
unsigned char *data, size_t data_len, void *user_data)
|
unsigned char *data, size_t data_len, void *user_data)
|
||||||
{
|
{
|
||||||
struct upekts_dev *upekdev = dev->priv;
|
struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev);
|
||||||
struct fpi_ssm *ssm = user_data;
|
fpi_ssm *ssm = user_data;
|
||||||
|
|
||||||
if (status != READ_MSG_RESPONSE) {
|
if (status != READ_MSG_RESPONSE) {
|
||||||
fp_err("expected response, got %d seq=%x", status, seq);
|
fp_err("expected response, got %d seq=%x", status, seq);
|
||||||
fpi_ssm_mark_aborted(ssm, -1);
|
fpi_ssm_mark_failed(ssm, -1);
|
||||||
} else if (subcmd != 0) {
|
} else if (subcmd != 0) {
|
||||||
fp_warn("expected response to subcmd 0, got response to %02x",
|
fp_warn("expected response to subcmd 0, got response to %02x",
|
||||||
subcmd);
|
subcmd);
|
||||||
fpi_ssm_mark_aborted(ssm, -1);
|
fpi_ssm_mark_failed(ssm, -1);
|
||||||
} else if (seq != upekdev->seq) {
|
} else if (seq != upekdev->seq) {
|
||||||
fp_err("expected response to cmd seq=%02x, got response to %02x",
|
fp_err("expected response to cmd seq=%02x, got response to %02x",
|
||||||
upekdev->seq, seq);
|
upekdev->seq, seq);
|
||||||
fpi_ssm_mark_aborted(ssm, -1);
|
fpi_ssm_mark_failed(ssm, -1);
|
||||||
} else {
|
} else {
|
||||||
fpi_ssm_next_state(ssm);
|
fpi_ssm_next_state(ssm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void enroll_start_sm_run_state(struct fpi_ssm *ssm)
|
static void enroll_start_sm_run_state(fpi_ssm *ssm, struct fp_dev *dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_dev *dev = ssm->dev;
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
switch (ssm->cur_state) {
|
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||||
case RUN_INITSM: ;
|
case RUN_INITSM: ;
|
||||||
struct fpi_ssm *initsm = initsm_new(dev);
|
fpi_ssm *initsm = initsm_new(dev, ssm);
|
||||||
initsm->priv = ssm;
|
|
||||||
fpi_ssm_start(initsm, enroll_start_sm_cb_initsm);
|
fpi_ssm_start(initsm, enroll_start_sm_cb_initsm);
|
||||||
break;
|
break;
|
||||||
case ENROLL_INIT: ;
|
case ENROLL_INIT: ;
|
||||||
@@ -976,7 +925,7 @@ static void enroll_start_sm_run_state(struct fpi_ssm *ssm)
|
|||||||
transfer = alloc_send_cmd28_transfer(dev, 0x02, enroll_init,
|
transfer = alloc_send_cmd28_transfer(dev, 0x02, enroll_init,
|
||||||
sizeof(enroll_init), enroll_start_sm_cb_init, ssm);
|
sizeof(enroll_init), enroll_start_sm_cb_init, ssm);
|
||||||
if (!transfer) {
|
if (!transfer) {
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
fpi_ssm_mark_failed(ssm, -ENOMEM);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -984,7 +933,7 @@ static void enroll_start_sm_run_state(struct fpi_ssm *ssm)
|
|||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
g_free(transfer->buffer);
|
g_free(transfer->buffer);
|
||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
fpi_ssm_mark_aborted(ssm, r);
|
fpi_ssm_mark_failed(ssm, r);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case READ_ENROLL_MSG28: ;
|
case READ_ENROLL_MSG28: ;
|
||||||
@@ -994,7 +943,7 @@ static void enroll_start_sm_run_state(struct fpi_ssm *ssm)
|
|||||||
* include a 30 01 poll somewhere? */
|
* include a 30 01 poll somewhere? */
|
||||||
r = read_msg_async(dev, enroll_start_sm_cb_msg28, ssm);
|
r = read_msg_async(dev, enroll_start_sm_cb_msg28, ssm);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
fpi_ssm_mark_aborted(ssm, r);
|
fpi_ssm_mark_failed(ssm, r);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1004,12 +953,12 @@ static void enroll_iterate(struct fp_dev *dev);
|
|||||||
static void e_handle_resp00(struct fp_dev *dev, unsigned char *data,
|
static void e_handle_resp00(struct fp_dev *dev, unsigned char *data,
|
||||||
size_t data_len)
|
size_t data_len)
|
||||||
{
|
{
|
||||||
struct upekts_dev *upekdev = dev->priv;
|
struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev);
|
||||||
unsigned char status;
|
unsigned char status;
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
|
||||||
if (data_len != 14) {
|
if (data_len != 14) {
|
||||||
fp_err("received 3001 poll response of %d bytes?", data_len);
|
fp_err("received 3001 poll response of %lu bytes?", data_len);
|
||||||
fpi_drvcb_enroll_stage_completed(dev, -EPROTO, NULL, NULL);
|
fpi_drvcb_enroll_stage_completed(dev, -EPROTO, NULL, NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1021,6 +970,9 @@ static void e_handle_resp00(struct fp_dev *dev, unsigned char *data,
|
|||||||
case 0x0c:
|
case 0x0c:
|
||||||
case 0x0d:
|
case 0x0d:
|
||||||
case 0x0e:
|
case 0x0e:
|
||||||
|
case 0x26:
|
||||||
|
case 0x27:
|
||||||
|
case 0x2e:
|
||||||
/* if we previously completed a non-last enrollment stage, we'll
|
/* if we previously completed a non-last enrollment stage, we'll
|
||||||
* get this code to indicate successful stage completion */
|
* get this code to indicate successful stage completion */
|
||||||
if (upekdev->enroll_passed) {
|
if (upekdev->enroll_passed) {
|
||||||
@@ -1081,7 +1033,7 @@ static void e_handle_resp02(struct fp_dev *dev, unsigned char *data,
|
|||||||
int result = -EPROTO;
|
int result = -EPROTO;
|
||||||
|
|
||||||
if (data_len < sizeof(scan_comp)) {
|
if (data_len < sizeof(scan_comp)) {
|
||||||
fp_err("fingerprint data too short (%d bytes)", data_len);
|
fp_err("fingerprint data too short (%lu bytes)", data_len);
|
||||||
} else if (memcmp(data, scan_comp, sizeof(scan_comp)) != 0) {
|
} else if (memcmp(data, scan_comp, sizeof(scan_comp)) != 0) {
|
||||||
fp_err("unrecognised data prefix %x %x %x %x %x",
|
fp_err("unrecognised data prefix %x %x %x %x %x",
|
||||||
data[0], data[1], data[2], data[3], data[4]);
|
data[0], data[1], data[2], data[3], data[4]);
|
||||||
@@ -1090,7 +1042,7 @@ static void e_handle_resp02(struct fp_dev *dev, unsigned char *data,
|
|||||||
item = fpi_print_data_item_new(data_len - sizeof(scan_comp));
|
item = fpi_print_data_item_new(data_len - sizeof(scan_comp));
|
||||||
memcpy(item->data, data + sizeof(scan_comp),
|
memcpy(item->data, data + sizeof(scan_comp),
|
||||||
data_len - sizeof(scan_comp));
|
data_len - sizeof(scan_comp));
|
||||||
fdata->prints = g_slist_prepend(fdata->prints, item);
|
fpi_print_data_add_item(fdata, item);
|
||||||
|
|
||||||
result = FP_ENROLL_COMPLETE;
|
result = FP_ENROLL_COMPLETE;
|
||||||
}
|
}
|
||||||
@@ -1153,12 +1105,11 @@ static void enroll_iterate(struct fp_dev *dev)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void enroll_started(struct fpi_ssm *ssm)
|
static void enroll_started(fpi_ssm *ssm, struct fp_dev *dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_dev *dev = ssm->dev;
|
fpi_drvcb_enroll_started(dev, fpi_ssm_get_error(ssm));
|
||||||
fpi_drvcb_enroll_started(dev, ssm->error);
|
|
||||||
|
|
||||||
if (!ssm->error)
|
if (!fpi_ssm_get_error(ssm))
|
||||||
enroll_iterate(dev);
|
enroll_iterate(dev);
|
||||||
|
|
||||||
fpi_ssm_free(ssm);
|
fpi_ssm_free(ssm);
|
||||||
@@ -1166,41 +1117,41 @@ static void enroll_started(struct fpi_ssm *ssm)
|
|||||||
|
|
||||||
static int enroll_start(struct fp_dev *dev)
|
static int enroll_start(struct fp_dev *dev)
|
||||||
{
|
{
|
||||||
struct upekts_dev *upekdev = dev->priv;
|
struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev);
|
||||||
|
|
||||||
/* do_init state machine first */
|
/* do_init state machine first */
|
||||||
struct fpi_ssm *ssm = fpi_ssm_new(dev, enroll_start_sm_run_state,
|
fpi_ssm *ssm = fpi_ssm_new(dev, enroll_start_sm_run_state,
|
||||||
ENROLL_START_NUM_STATES);
|
ENROLL_START_NUM_STATES, NULL);
|
||||||
|
|
||||||
upekdev->enroll_passed = FALSE;
|
upekdev->enroll_passed = FALSE;
|
||||||
fpi_ssm_start(ssm, enroll_started);
|
fpi_ssm_start(ssm, enroll_started);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void enroll_stop_deinit_cb(struct fpi_ssm *ssm)
|
static void enroll_stop_deinit_cb(fpi_ssm *ssm, struct fp_dev *dev, void *user_data)
|
||||||
{
|
{
|
||||||
/* don't really care about errors */
|
/* don't really care about errors */
|
||||||
fpi_drvcb_enroll_stopped(ssm->dev);
|
fpi_drvcb_enroll_stopped(dev);
|
||||||
fpi_ssm_free(ssm);
|
fpi_ssm_free(ssm);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int enroll_stop(struct fp_dev *dev)
|
static int enroll_stop(struct fp_dev *dev)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = deinitsm_new(dev);
|
fpi_ssm *ssm = deinitsm_new(dev);
|
||||||
fpi_ssm_start(ssm, enroll_stop_deinit_cb);
|
fpi_ssm_start(ssm, enroll_stop_deinit_cb);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void verify_stop_deinit_cb(struct fpi_ssm *ssm)
|
static void verify_stop_deinit_cb(fpi_ssm *ssm, struct fp_dev *dev, void *user_data)
|
||||||
{
|
{
|
||||||
/* don't really care about errors */
|
/* don't really care about errors */
|
||||||
fpi_drvcb_verify_stopped(ssm->dev);
|
fpi_drvcb_verify_stopped(dev);
|
||||||
fpi_ssm_free(ssm);
|
fpi_ssm_free(ssm);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_verify_stop(struct fp_dev *dev)
|
static void do_verify_stop(struct fp_dev *dev)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = deinitsm_new(dev);
|
fpi_ssm *ssm = deinitsm_new(dev);
|
||||||
fpi_ssm_start(ssm, verify_stop_deinit_cb);
|
fpi_ssm_start(ssm, verify_stop_deinit_cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1217,11 +1168,14 @@ enum {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* Called when the device initialization state machine completes */
|
/* Called when the device initialization state machine completes */
|
||||||
static void verify_start_sm_cb_initsm(struct fpi_ssm *initsm)
|
static void verify_start_sm_cb_initsm(fpi_ssm *initsm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *verify_start_ssm = initsm->priv;
|
fpi_ssm *verify_start_ssm = user_data;
|
||||||
if (initsm->error)
|
int err;
|
||||||
fpi_ssm_mark_aborted(verify_start_ssm, initsm->error);
|
|
||||||
|
err = fpi_ssm_get_error(initsm);
|
||||||
|
if (err)
|
||||||
|
fpi_ssm_mark_failed(verify_start_ssm, err);
|
||||||
else
|
else
|
||||||
fpi_ssm_next_state(verify_start_ssm);
|
fpi_ssm_next_state(verify_start_ssm);
|
||||||
fpi_ssm_free(initsm);
|
fpi_ssm_free(initsm);
|
||||||
@@ -1229,30 +1183,28 @@ static void verify_start_sm_cb_initsm(struct fpi_ssm *initsm)
|
|||||||
|
|
||||||
static void verify_init_2803_cb(struct libusb_transfer *transfer)
|
static void verify_init_2803_cb(struct libusb_transfer *transfer)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
|
if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
else if (transfer->length != transfer->actual_length)
|
else if (transfer->length != transfer->actual_length)
|
||||||
fpi_ssm_mark_aborted(ssm, -EPROTO);
|
fpi_ssm_mark_failed(ssm, -EPROTO);
|
||||||
else
|
else
|
||||||
fpi_ssm_next_state(ssm);
|
fpi_ssm_next_state(ssm);
|
||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void verify_start_sm_run_state(struct fpi_ssm *ssm)
|
static void verify_start_sm_run_state(fpi_ssm *ssm, struct fp_dev *dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_dev *dev = ssm->dev;
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
switch (ssm->cur_state) {
|
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||||
case VERIFY_RUN_INITSM: ;
|
case VERIFY_RUN_INITSM: ;
|
||||||
struct fpi_ssm *initsm = initsm_new(dev);
|
fpi_ssm *initsm = initsm_new(dev, ssm);
|
||||||
initsm->priv = ssm;
|
|
||||||
fpi_ssm_start(initsm, verify_start_sm_cb_initsm);
|
fpi_ssm_start(initsm, verify_start_sm_cb_initsm);
|
||||||
break;
|
break;
|
||||||
case VERIFY_INIT: ;
|
case VERIFY_INIT: ;
|
||||||
struct fp_print_data *print = dev->verify_data;
|
struct fp_print_data *print = fpi_dev_get_verify_data(dev);
|
||||||
struct fp_print_data_item *item = print->prints->data;
|
struct fp_print_data_item *item = fpi_print_data_get_item(print);
|
||||||
size_t data_len = sizeof(verify_hdr) + item->length;
|
size_t data_len = sizeof(verify_hdr) + item->length;
|
||||||
unsigned char *data = g_malloc(data_len);
|
unsigned char *data = g_malloc(data_len);
|
||||||
struct libusb_transfer *transfer;
|
struct libusb_transfer *transfer;
|
||||||
@@ -1263,7 +1215,7 @@ static void verify_start_sm_run_state(struct fpi_ssm *ssm)
|
|||||||
verify_init_2803_cb, ssm);
|
verify_init_2803_cb, ssm);
|
||||||
g_free(data);
|
g_free(data);
|
||||||
if (!transfer) {
|
if (!transfer) {
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
fpi_ssm_mark_failed(ssm, -ENOMEM);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1271,7 +1223,7 @@ static void verify_start_sm_run_state(struct fpi_ssm *ssm)
|
|||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
g_free(transfer->buffer);
|
g_free(transfer->buffer);
|
||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1286,7 +1238,7 @@ static void v_handle_resp00(struct fp_dev *dev, unsigned char *data,
|
|||||||
int r = 0;
|
int r = 0;
|
||||||
|
|
||||||
if (data_len != 14) {
|
if (data_len != 14) {
|
||||||
fp_err("received 3001 poll response of %d bytes?", data_len);
|
fp_err("received 3001 poll response of %lu bytes?", data_len);
|
||||||
r = -EPROTO;
|
r = -EPROTO;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@@ -1357,7 +1309,7 @@ static void verify_rd2800_cb(struct fp_dev *dev, enum read_msg_status msgstat,
|
|||||||
uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len,
|
uint8_t seq, unsigned char subcmd, unsigned char *data, size_t data_len,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
struct upekts_dev *upekdev = dev->priv;
|
struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev);
|
||||||
|
|
||||||
if (msgstat != READ_MSG_RESPONSE) {
|
if (msgstat != READ_MSG_RESPONSE) {
|
||||||
fp_err("expected response, got %d seq=%x", msgstat, seq);
|
fp_err("expected response, got %d seq=%x", msgstat, seq);
|
||||||
@@ -1396,7 +1348,7 @@ static void verify_wr2800_cb(struct libusb_transfer *transfer)
|
|||||||
|
|
||||||
static void verify_iterate(struct fp_dev *dev)
|
static void verify_iterate(struct fp_dev *dev)
|
||||||
{
|
{
|
||||||
struct upekts_dev *upekdev = dev->priv;
|
struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev);
|
||||||
|
|
||||||
if (upekdev->stop_verify) {
|
if (upekdev->stop_verify) {
|
||||||
do_verify_stop(dev);
|
do_verify_stop(dev);
|
||||||
@@ -1429,13 +1381,12 @@ static void verify_iterate(struct fp_dev *dev)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void verify_started(struct fpi_ssm *ssm)
|
static void verify_started(fpi_ssm *ssm, struct fp_dev *dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_dev *dev = ssm->dev;
|
struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev);
|
||||||
struct upekts_dev *upekdev = dev->priv;
|
|
||||||
|
|
||||||
fpi_drvcb_verify_started(dev, ssm->error);
|
fpi_drvcb_verify_started(dev, fpi_ssm_get_error(ssm));
|
||||||
if (!ssm->error) {
|
if (!fpi_ssm_get_error(ssm)) {
|
||||||
upekdev->first_verify_iteration = TRUE;
|
upekdev->first_verify_iteration = TRUE;
|
||||||
verify_iterate(dev);
|
verify_iterate(dev);
|
||||||
}
|
}
|
||||||
@@ -1445,9 +1396,9 @@ static void verify_started(struct fpi_ssm *ssm)
|
|||||||
|
|
||||||
static int verify_start(struct fp_dev *dev)
|
static int verify_start(struct fp_dev *dev)
|
||||||
{
|
{
|
||||||
struct upekts_dev *upekdev = dev->priv;
|
struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev);
|
||||||
struct fpi_ssm *ssm = fpi_ssm_new(dev, verify_start_sm_run_state,
|
fpi_ssm *ssm = fpi_ssm_new(dev, verify_start_sm_run_state,
|
||||||
VERIFY_NUM_STATES);
|
VERIFY_NUM_STATES, NULL);
|
||||||
upekdev->stop_verify = FALSE;
|
upekdev->stop_verify = FALSE;
|
||||||
fpi_ssm_start(ssm, verify_started);
|
fpi_ssm_start(ssm, verify_started);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1455,7 +1406,7 @@ static int verify_start(struct fp_dev *dev)
|
|||||||
|
|
||||||
static int verify_stop(struct fp_dev *dev, gboolean iterating)
|
static int verify_stop(struct fp_dev *dev, gboolean iterating)
|
||||||
{
|
{
|
||||||
struct upekts_dev *upekdev = dev->priv;
|
struct upekts_dev *upekdev = FP_INSTANCE_DATA(dev);
|
||||||
|
|
||||||
if (!iterating)
|
if (!iterating)
|
||||||
do_verify_stop(dev);
|
do_verify_stop(dev);
|
||||||
|
|||||||
@@ -20,17 +20,10 @@
|
|||||||
|
|
||||||
#define FP_COMPONENT "uru4000"
|
#define FP_COMPONENT "uru4000"
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include <nss.h>
|
#include <nss.h>
|
||||||
#include <pk11pub.h>
|
#include <pk11pub.h>
|
||||||
#include <libusb.h>
|
|
||||||
|
|
||||||
#include <fp_internal.h>
|
#include "drivers_api.h"
|
||||||
|
|
||||||
#include "driver_ids.h"
|
|
||||||
|
|
||||||
#define EP_INTR (1 | LIBUSB_ENDPOINT_IN)
|
#define EP_INTR (1 | LIBUSB_ENDPOINT_IN)
|
||||||
#define EP_DATA (2 | LIBUSB_ENDPOINT_IN)
|
#define EP_DATA (2 | LIBUSB_ENDPOINT_IN)
|
||||||
@@ -45,6 +38,8 @@
|
|||||||
#define IMAGE_HEIGHT 290
|
#define IMAGE_HEIGHT 290
|
||||||
#define IMAGE_WIDTH 384
|
#define IMAGE_WIDTH 384
|
||||||
|
|
||||||
|
#define ENC_THRESHOLD 5000
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
IRQDATA_SCANPWR_ON = 0x56aa,
|
IRQDATA_SCANPWR_ON = 0x56aa,
|
||||||
IRQDATA_FINGER_ON = 0x0101,
|
IRQDATA_FINGER_ON = 0x0101,
|
||||||
@@ -125,9 +120,10 @@ struct uru4k_dev {
|
|||||||
unsigned char last_reg_rd[16];
|
unsigned char last_reg_rd[16];
|
||||||
unsigned char last_hwstat;
|
unsigned char last_hwstat;
|
||||||
|
|
||||||
struct libusb_transfer *irq_transfer;
|
fpi_usb_transfer *irq_transfer;
|
||||||
struct libusb_transfer *img_transfer;
|
fpi_usb_transfer *img_transfer;
|
||||||
void *img_data;
|
void *img_data;
|
||||||
|
int img_data_actual_length;
|
||||||
uint16_t img_lines_done, img_block;
|
uint16_t img_lines_done, img_block;
|
||||||
uint32_t img_enc_seed;
|
uint32_t img_enc_seed;
|
||||||
|
|
||||||
@@ -140,7 +136,7 @@ struct uru4k_dev {
|
|||||||
unsigned char powerup_hwstat;
|
unsigned char powerup_hwstat;
|
||||||
|
|
||||||
int scanpwr_irq_timeouts;
|
int scanpwr_irq_timeouts;
|
||||||
struct fpi_timeout *scanpwr_irq_timeout;
|
fpi_timeout *scanpwr_irq_timeout;
|
||||||
|
|
||||||
int fwfixer_offset;
|
int fwfixer_offset;
|
||||||
unsigned char fwfixer_value;
|
unsigned char fwfixer_value;
|
||||||
@@ -191,13 +187,10 @@ static int write_regs(struct fp_img_dev *dev, uint16_t first_reg,
|
|||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
struct write_regs_data *wrdata;
|
struct write_regs_data *wrdata;
|
||||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||||
unsigned char *data;
|
unsigned char *data;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (!transfer)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
wrdata = g_malloc(sizeof(*wrdata));
|
wrdata = g_malloc(sizeof(*wrdata));
|
||||||
wrdata->dev = dev;
|
wrdata->dev = dev;
|
||||||
wrdata->callback = callback;
|
wrdata->callback = callback;
|
||||||
@@ -206,7 +199,7 @@ static int write_regs(struct fp_img_dev *dev, uint16_t first_reg,
|
|||||||
data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE + num_regs);
|
data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE + num_regs);
|
||||||
memcpy(data + LIBUSB_CONTROL_SETUP_SIZE, values, num_regs);
|
memcpy(data + LIBUSB_CONTROL_SETUP_SIZE, values, num_regs);
|
||||||
libusb_fill_control_setup(data, CTRL_OUT, USB_RQ, first_reg, 0, num_regs);
|
libusb_fill_control_setup(data, CTRL_OUT, USB_RQ, first_reg, 0, num_regs);
|
||||||
libusb_fill_control_transfer(transfer, dev->udev, data, write_regs_cb,
|
libusb_fill_control_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), data, write_regs_cb,
|
||||||
wrdata, CTRL_TIMEOUT);
|
wrdata, CTRL_TIMEOUT);
|
||||||
|
|
||||||
r = libusb_submit_transfer(transfer);
|
r = libusb_submit_transfer(transfer);
|
||||||
@@ -258,13 +251,10 @@ static int read_regs(struct fp_img_dev *dev, uint16_t first_reg,
|
|||||||
uint16_t num_regs, read_regs_cb_fn callback, void *user_data)
|
uint16_t num_regs, read_regs_cb_fn callback, void *user_data)
|
||||||
{
|
{
|
||||||
struct read_regs_data *rrdata;
|
struct read_regs_data *rrdata;
|
||||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||||
unsigned char *data;
|
unsigned char *data;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (!transfer)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
rrdata = g_malloc(sizeof(*rrdata));
|
rrdata = g_malloc(sizeof(*rrdata));
|
||||||
rrdata->dev = dev;
|
rrdata->dev = dev;
|
||||||
rrdata->callback = callback;
|
rrdata->callback = callback;
|
||||||
@@ -272,7 +262,7 @@ static int read_regs(struct fp_img_dev *dev, uint16_t first_reg,
|
|||||||
|
|
||||||
data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE + num_regs);
|
data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE + num_regs);
|
||||||
libusb_fill_control_setup(data, CTRL_IN, USB_RQ, first_reg, 0, num_regs);
|
libusb_fill_control_setup(data, CTRL_IN, USB_RQ, first_reg, 0, num_regs);
|
||||||
libusb_fill_control_transfer(transfer, dev->udev, data, read_regs_cb,
|
libusb_fill_control_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), data, read_regs_cb,
|
||||||
rrdata, CTRL_TIMEOUT);
|
rrdata, CTRL_TIMEOUT);
|
||||||
|
|
||||||
r = libusb_submit_transfer(transfer);
|
r = libusb_submit_transfer(transfer);
|
||||||
@@ -306,30 +296,30 @@ static int read_regs(struct fp_img_dev *dev, uint16_t first_reg,
|
|||||||
*
|
*
|
||||||
* BIT 1: IRQ PENDING
|
* BIT 1: IRQ PENDING
|
||||||
* Just had a brainwave. This bit is set when the device is trying to deliver
|
* Just had a brainwave. This bit is set when the device is trying to deliver
|
||||||
* and interrupt to the host. Maybe?
|
* an interrupt to the host. Maybe?
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void response_cb(struct fp_img_dev *dev, int status, void *user_data)
|
static void response_cb(struct fp_img_dev *dev, int status, void *user_data)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = user_data;
|
fpi_ssm *ssm = user_data;
|
||||||
if (status == 0)
|
if (status == 0)
|
||||||
fpi_ssm_next_state(ssm);
|
fpi_ssm_next_state(ssm);
|
||||||
else
|
else
|
||||||
fpi_ssm_mark_aborted(ssm, status);
|
fpi_ssm_mark_failed(ssm, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void challenge_cb(struct fp_img_dev *dev, int status,
|
static void challenge_cb(struct fp_img_dev *dev, int status,
|
||||||
uint16_t num_regs, unsigned char *data, void *user_data)
|
uint16_t num_regs, unsigned char *data, void *user_data)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = user_data;
|
fpi_ssm *ssm = user_data;
|
||||||
struct uru4k_dev *urudev = dev->priv;
|
struct uru4k_dev *urudev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
unsigned char *respdata;
|
unsigned char *respdata;
|
||||||
PK11Context *ctx;
|
PK11Context *ctx;
|
||||||
int r, outlen;
|
int r, outlen;
|
||||||
|
|
||||||
r = status;
|
r = status;
|
||||||
if (status != 0) {
|
if (status != 0) {
|
||||||
fpi_ssm_mark_aborted(ssm, status);
|
fpi_ssm_mark_failed(ssm, status);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -351,7 +341,7 @@ static void challenge_cb(struct fp_img_dev *dev, int status,
|
|||||||
g_free(respdata);
|
g_free(respdata);
|
||||||
}
|
}
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
fpi_ssm_mark_aborted(ssm, r);
|
fpi_ssm_mark_failed(ssm, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -359,15 +349,16 @@ static void challenge_cb(struct fp_img_dev *dev, int status,
|
|||||||
* authentication scheme, where the device challenges the authenticity of the
|
* authentication scheme, where the device challenges the authenticity of the
|
||||||
* driver.
|
* driver.
|
||||||
*/
|
*/
|
||||||
static void sm_do_challenge_response(struct fpi_ssm *ssm)
|
static void
|
||||||
|
sm_do_challenge_response(fpi_ssm *ssm,
|
||||||
|
struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
fp_dbg("");
|
G_DEBUG_HERE();
|
||||||
r = read_regs(dev, REG_CHALLENGE, CR_LENGTH, challenge_cb, ssm);
|
r = read_regs(dev, REG_CHALLENGE, CR_LENGTH, challenge_cb, ssm);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
fpi_ssm_mark_aborted(ssm, r);
|
fpi_ssm_mark_failed(ssm, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
/***** INTERRUPT HANDLING *****/
|
/***** INTERRUPT HANDLING *****/
|
||||||
@@ -376,10 +367,13 @@ static void sm_do_challenge_response(struct fpi_ssm *ssm)
|
|||||||
|
|
||||||
static int start_irq_handler(struct fp_img_dev *dev);
|
static int start_irq_handler(struct fp_img_dev *dev);
|
||||||
|
|
||||||
static void irq_handler(struct libusb_transfer *transfer)
|
static void irq_handler(struct libusb_transfer *transfer,
|
||||||
|
struct fp_dev *_dev,
|
||||||
|
fpi_ssm *ssm,
|
||||||
|
void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = transfer->user_data;
|
struct fp_img_dev *dev = FP_IMG_DEV(_dev);
|
||||||
struct uru4k_dev *urudev = dev->priv;
|
struct uru4k_dev *urudev = FP_INSTANCE_DATA(_dev);
|
||||||
unsigned char *data = transfer->buffer;
|
unsigned char *data = transfer->buffer;
|
||||||
uint16_t type;
|
uint16_t type;
|
||||||
int r = 0;
|
int r = 0;
|
||||||
@@ -401,8 +395,6 @@ static void irq_handler(struct libusb_transfer *transfer)
|
|||||||
|
|
||||||
type = GUINT16_FROM_BE(*((uint16_t *) data));
|
type = GUINT16_FROM_BE(*((uint16_t *) data));
|
||||||
fp_dbg("recv irq type %04x", type);
|
fp_dbg("recv irq type %04x", type);
|
||||||
g_free(data);
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
|
|
||||||
/* The 0800 interrupt seems to indicate imminent failure (0 bytes transfer)
|
/* The 0800 interrupt seems to indicate imminent failure (0 bytes transfer)
|
||||||
* of the next scan. It still appears on occasion. */
|
* of the next scan. It still appears on occasion. */
|
||||||
@@ -418,47 +410,43 @@ static void irq_handler(struct libusb_transfer *transfer)
|
|||||||
if (r == 0)
|
if (r == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
transfer = NULL;
|
|
||||||
data = NULL;
|
|
||||||
err:
|
err:
|
||||||
if (urudev->irq_cb)
|
if (urudev->irq_cb)
|
||||||
urudev->irq_cb(dev, r, 0, urudev->irq_cb_data);
|
urudev->irq_cb(dev, r, 0, urudev->irq_cb_data);
|
||||||
out:
|
out:
|
||||||
g_free(data);
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
urudev->irq_transfer = NULL;
|
urudev->irq_transfer = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int start_irq_handler(struct fp_img_dev *dev)
|
static int start_irq_handler(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct uru4k_dev *urudev = dev->priv;
|
struct uru4k_dev *urudev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
fpi_usb_transfer *transfer;
|
||||||
unsigned char *data;
|
unsigned char *data;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (!transfer)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
data = g_malloc(IRQ_LENGTH);
|
data = g_malloc(IRQ_LENGTH);
|
||||||
libusb_fill_bulk_transfer(transfer, dev->udev, EP_INTR, data, IRQ_LENGTH,
|
transfer = fpi_usb_fill_bulk_transfer(FP_DEV(dev),
|
||||||
irq_handler, dev, 0);
|
NULL,
|
||||||
|
EP_INTR,
|
||||||
|
data,
|
||||||
|
IRQ_LENGTH,
|
||||||
|
irq_handler,
|
||||||
|
NULL,
|
||||||
|
0);
|
||||||
|
|
||||||
urudev->irq_transfer = transfer;
|
urudev->irq_transfer = transfer;
|
||||||
r = libusb_submit_transfer(transfer);
|
r = fpi_usb_submit_transfer(transfer);
|
||||||
if (r < 0) {
|
if (r < 0)
|
||||||
g_free(data);
|
|
||||||
libusb_free_transfer(transfer);
|
|
||||||
urudev->irq_transfer = NULL;
|
urudev->irq_transfer = NULL;
|
||||||
}
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void stop_irq_handler(struct fp_img_dev *dev, irqs_stopped_cb_fn cb)
|
static void stop_irq_handler(struct fp_img_dev *dev, irqs_stopped_cb_fn cb)
|
||||||
{
|
{
|
||||||
struct uru4k_dev *urudev = dev->priv;
|
struct uru4k_dev *urudev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
struct libusb_transfer *transfer = urudev->irq_transfer;
|
fpi_usb_transfer *transfer = urudev->irq_transfer;
|
||||||
if (transfer) {
|
if (transfer) {
|
||||||
libusb_cancel_transfer(transfer);
|
fpi_usb_cancel_transfer(transfer);
|
||||||
urudev->irqs_stopped_cb = cb;
|
urudev->irqs_stopped_cb = cb;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -489,7 +477,7 @@ static void change_state_write_reg_cb(struct fp_img_dev *dev, int status,
|
|||||||
|
|
||||||
static int dev_change_state(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
static int dev_change_state(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
||||||
{
|
{
|
||||||
struct uru4k_dev *urudev = dev->priv;
|
struct uru4k_dev *urudev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case IMGDEV_STATE_INACTIVE:
|
case IMGDEV_STATE_INACTIVE:
|
||||||
@@ -513,37 +501,43 @@ static int dev_change_state(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
|||||||
|
|
||||||
static void sm_write_reg_cb(struct fp_img_dev *dev, int result, void *user_data)
|
static void sm_write_reg_cb(struct fp_img_dev *dev, int result, void *user_data)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = user_data;
|
fpi_ssm *ssm = user_data;
|
||||||
|
|
||||||
if (result)
|
if (result)
|
||||||
fpi_ssm_mark_aborted(ssm, result);
|
fpi_ssm_mark_failed(ssm, result);
|
||||||
else
|
else
|
||||||
fpi_ssm_next_state(ssm);
|
fpi_ssm_next_state(ssm);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sm_write_regs(struct fpi_ssm *ssm, uint16_t first_reg, uint16_t num_regs,
|
static void
|
||||||
void *data)
|
sm_write_regs(fpi_ssm *ssm,
|
||||||
|
struct fp_img_dev *dev,
|
||||||
|
uint16_t first_reg,
|
||||||
|
uint16_t num_regs,
|
||||||
|
void *data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
|
||||||
int r = write_regs(dev, first_reg, num_regs, data, sm_write_reg_cb, ssm);
|
int r = write_regs(dev, first_reg, num_regs, data, sm_write_reg_cb, ssm);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
fpi_ssm_mark_aborted(ssm, r);
|
fpi_ssm_mark_failed(ssm, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sm_write_reg(struct fpi_ssm *ssm, uint16_t reg,
|
static void
|
||||||
unsigned char value)
|
sm_write_reg(fpi_ssm *ssm,
|
||||||
|
struct fp_img_dev *dev,
|
||||||
|
uint16_t reg,
|
||||||
|
unsigned char value)
|
||||||
{
|
{
|
||||||
sm_write_regs(ssm, reg, 1, &value);
|
sm_write_regs(ssm, dev, reg, 1, &value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sm_read_reg_cb(struct fp_img_dev *dev, int result,
|
static void sm_read_reg_cb(struct fp_img_dev *dev, int result,
|
||||||
uint16_t num_regs, unsigned char *data, void *user_data)
|
uint16_t num_regs, unsigned char *data, void *user_data)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = user_data;
|
fpi_ssm *ssm = user_data;
|
||||||
struct uru4k_dev *urudev = dev->priv;
|
struct uru4k_dev *urudev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
fpi_ssm_mark_aborted(ssm, result);
|
fpi_ssm_mark_failed(ssm, result);
|
||||||
} else {
|
} else {
|
||||||
memcpy(urudev->last_reg_rd, data, num_regs);
|
memcpy(urudev->last_reg_rd, data, num_regs);
|
||||||
fp_dbg("reg value %x", urudev->last_reg_rd[0]);
|
fp_dbg("reg value %x", urudev->last_reg_rd[0]);
|
||||||
@@ -551,32 +545,42 @@ static void sm_read_reg_cb(struct fp_img_dev *dev, int result,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sm_read_regs(struct fpi_ssm *ssm, uint16_t reg, uint16_t num_regs)
|
#define member_size(type, member) sizeof(((type *)0)->member)
|
||||||
|
|
||||||
|
static void
|
||||||
|
sm_read_regs(fpi_ssm *ssm,
|
||||||
|
struct fp_img_dev *dev,
|
||||||
|
uint16_t reg,
|
||||||
|
uint16_t num_regs)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
|
||||||
struct uru4k_dev *urudev = dev->priv;
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (num_regs > sizeof(urudev->last_reg_rd)) {
|
if (num_regs > member_size(struct uru4k_dev, last_reg_rd)) {
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fp_dbg("read %d regs at %x", num_regs, reg);
|
fp_dbg("read %d regs at %x", num_regs, reg);
|
||||||
r = read_regs(dev, reg, num_regs, sm_read_reg_cb, ssm);
|
r = read_regs(dev, reg, num_regs, sm_read_reg_cb, ssm);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
fpi_ssm_mark_aborted(ssm, r);
|
fpi_ssm_mark_failed(ssm, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sm_read_reg(struct fpi_ssm *ssm, uint16_t reg)
|
static void
|
||||||
|
sm_read_reg(fpi_ssm *ssm,
|
||||||
|
struct fp_img_dev *dev,
|
||||||
|
uint16_t reg)
|
||||||
{
|
{
|
||||||
sm_read_regs(ssm, reg, 1);
|
sm_read_regs(ssm, dev, reg, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sm_set_hwstat(struct fpi_ssm *ssm, unsigned char value)
|
static void
|
||||||
|
sm_set_hwstat(fpi_ssm *ssm,
|
||||||
|
struct fp_img_dev *dev,
|
||||||
|
unsigned char value)
|
||||||
{
|
{
|
||||||
fp_dbg("set %02x", value);
|
fp_dbg("set %02x", value);
|
||||||
sm_write_reg(ssm, REG_HWSTAT, value);
|
sm_write_reg(ssm, dev, REG_HWSTAT, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/***** IMAGING LOOP *****/
|
/***** IMAGING LOOP *****/
|
||||||
@@ -590,28 +594,6 @@ enum imaging_states {
|
|||||||
IMAGING_NUM_STATES
|
IMAGING_NUM_STATES
|
||||||
};
|
};
|
||||||
|
|
||||||
static void image_transfer_cb(struct libusb_transfer *transfer)
|
|
||||||
{
|
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
|
||||||
|
|
||||||
if (transfer->status == LIBUSB_TRANSFER_CANCELLED) {
|
|
||||||
fp_dbg("cancelled");
|
|
||||||
fpi_ssm_mark_aborted(ssm, -ECANCELED);
|
|
||||||
} else if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
|
||||||
fp_dbg("error");
|
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
|
||||||
} else {
|
|
||||||
fpi_ssm_next_state(ssm);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum {
|
|
||||||
BLOCKF_CHANGE_KEY = 0x80,
|
|
||||||
BLOCKF_NO_KEY_UPDATE = 0x04,
|
|
||||||
BLOCKF_ENCRYPTED = 0x02,
|
|
||||||
BLOCKF_NOT_PRESENT = 0x01,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct uru4k_image {
|
struct uru4k_image {
|
||||||
uint8_t unknown_00[4];
|
uint8_t unknown_00[4];
|
||||||
uint16_t num_lines;
|
uint16_t num_lines;
|
||||||
@@ -625,6 +607,33 @@ struct uru4k_image {
|
|||||||
uint8_t data[IMAGE_HEIGHT][IMAGE_WIDTH];
|
uint8_t data[IMAGE_HEIGHT][IMAGE_WIDTH];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void image_transfer_cb(struct libusb_transfer *transfer,
|
||||||
|
struct fp_dev *dev,
|
||||||
|
fpi_ssm *ssm,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
if (transfer->status == LIBUSB_TRANSFER_CANCELLED) {
|
||||||
|
fp_dbg("cancelled");
|
||||||
|
fpi_ssm_mark_failed(ssm, -ECANCELED);
|
||||||
|
} else if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||||
|
fp_dbg("error");
|
||||||
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
|
} else {
|
||||||
|
struct uru4k_dev *urudev = FP_INSTANCE_DATA(dev);
|
||||||
|
|
||||||
|
urudev->img_data = g_memdup(transfer->buffer, sizeof(struct uru4k_image));
|
||||||
|
urudev->img_data_actual_length = transfer->actual_length;
|
||||||
|
fpi_ssm_next_state(ssm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum {
|
||||||
|
BLOCKF_CHANGE_KEY = 0x80,
|
||||||
|
BLOCKF_NO_KEY_UPDATE = 0x04,
|
||||||
|
BLOCKF_ENCRYPTED = 0x02,
|
||||||
|
BLOCKF_NOT_PRESENT = 0x01,
|
||||||
|
};
|
||||||
|
|
||||||
static uint32_t update_key(uint32_t key)
|
static uint32_t update_key(uint32_t key)
|
||||||
{
|
{
|
||||||
/* linear feedback shift register
|
/* linear feedback shift register
|
||||||
@@ -659,57 +668,90 @@ static uint32_t do_decode(uint8_t *data, int num_bytes, uint32_t key)
|
|||||||
data[i] = data[i+1] ^ xorbyte;
|
data[i] = data[i+1] ^ xorbyte;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* the final byte is implictly zero */
|
/* the final byte is implicitly zero */
|
||||||
data[i] = 0;
|
data[i] = 0;
|
||||||
return update_key(key);
|
return update_key(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void imaging_run_state(struct fpi_ssm *ssm)
|
static int calc_dev2(struct uru4k_image *img)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
uint8_t *b[2] = { NULL, NULL };
|
||||||
struct uru4k_dev *urudev = dev->priv;
|
int res = 0, mean = 0, i, r, j, idx;
|
||||||
|
|
||||||
|
for (i = r = idx = 0; i < G_N_ELEMENTS(img->block_info) && idx < 2; i++) {
|
||||||
|
if (img->block_info[i].flags & BLOCKF_NOT_PRESENT)
|
||||||
|
continue;
|
||||||
|
for (j = 0; j < img->block_info[i].num_lines && idx < 2; j++)
|
||||||
|
b[idx++] = img->data[r++];
|
||||||
|
}
|
||||||
|
if (!b[0] || !b[1]) {
|
||||||
|
fp_dbg("NULL! %p %p", b[0], b[1]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
for (i = 0; i < IMAGE_WIDTH; i++)
|
||||||
|
mean += (int)b[0][i] + (int)b[1][i];
|
||||||
|
|
||||||
|
mean /= IMAGE_WIDTH;
|
||||||
|
|
||||||
|
for (i = 0; i < IMAGE_WIDTH; i++) {
|
||||||
|
int dev = (int)b[0][i] + (int)b[1][i] - mean;
|
||||||
|
res += dev * dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res / IMAGE_WIDTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void imaging_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
|
{
|
||||||
|
struct fp_img_dev *dev = user_data;
|
||||||
|
struct uru4k_dev *urudev = FP_INSTANCE_DATA(_dev);
|
||||||
struct uru4k_image *img = urudev->img_data;
|
struct uru4k_image *img = urudev->img_data;
|
||||||
struct fp_img *fpimg;
|
struct fp_img *fpimg;
|
||||||
uint32_t key;
|
uint32_t key;
|
||||||
uint8_t flags, num_lines;
|
uint8_t flags, num_lines;
|
||||||
int i, r, to;
|
int i, r, to, dev2;
|
||||||
char buf[5];
|
unsigned char buf[5];
|
||||||
|
|
||||||
switch (ssm->cur_state) {
|
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||||
case IMAGING_CAPTURE:
|
case IMAGING_CAPTURE:
|
||||||
urudev->img_lines_done = 0;
|
urudev->img_lines_done = 0;
|
||||||
urudev->img_block = 0;
|
urudev->img_block = 0;
|
||||||
libusb_fill_bulk_transfer(urudev->img_transfer, dev->udev, EP_DATA,
|
r = fpi_usb_submit_transfer(urudev->img_transfer);
|
||||||
urudev->img_data, sizeof(struct uru4k_image), image_transfer_cb, ssm, 0);
|
if (r < 0) {
|
||||||
r = libusb_submit_transfer(urudev->img_transfer);
|
urudev->img_transfer = NULL;
|
||||||
if (r < 0)
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
}
|
||||||
break;
|
break;
|
||||||
case IMAGING_SEND_INDEX:
|
case IMAGING_SEND_INDEX:
|
||||||
fp_dbg("hw header lines %d", img->num_lines);
|
fp_dbg("hw header lines %d", img->num_lines);
|
||||||
|
|
||||||
if (img->num_lines >= IMAGE_HEIGHT ||
|
if (img->num_lines >= IMAGE_HEIGHT ||
|
||||||
urudev->img_transfer->actual_length < img->num_lines * IMAGE_WIDTH + 64) {
|
urudev->img_data_actual_length < img->num_lines * IMAGE_WIDTH + 64) {
|
||||||
fp_err("bad captured image (%d lines) or size mismatch %d < %d",
|
fp_err("bad captured image (%d lines) or size mismatch %d < %d",
|
||||||
img->num_lines,
|
img->num_lines,
|
||||||
urudev->img_transfer->actual_length,
|
urudev->img_data_actual_length,
|
||||||
img->num_lines * IMAGE_WIDTH + 64);
|
img->num_lines * IMAGE_WIDTH + 64);
|
||||||
fpi_ssm_jump_to_state(ssm, IMAGING_CAPTURE);
|
fpi_ssm_jump_to_state(ssm, IMAGING_CAPTURE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!urudev->profile->encryption) {
|
if (!urudev->profile->encryption) {
|
||||||
fpi_ssm_jump_to_state(ssm, IMAGING_REPORT_IMAGE);
|
dev2 = calc_dev2(img);
|
||||||
return;
|
fp_dbg("dev2: %d", dev2);
|
||||||
|
if (dev2 < ENC_THRESHOLD) {
|
||||||
|
fpi_ssm_jump_to_state(ssm, IMAGING_REPORT_IMAGE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fp_info("image seems to be encrypted");
|
||||||
}
|
}
|
||||||
buf[0] = img->key_number;
|
buf[0] = img->key_number;
|
||||||
buf[1] = urudev->img_enc_seed;
|
buf[1] = urudev->img_enc_seed;
|
||||||
buf[2] = urudev->img_enc_seed >> 8;
|
buf[2] = urudev->img_enc_seed >> 8;
|
||||||
buf[3] = urudev->img_enc_seed >> 16;
|
buf[3] = urudev->img_enc_seed >> 16;
|
||||||
buf[4] = urudev->img_enc_seed >> 24;
|
buf[4] = urudev->img_enc_seed >> 24;
|
||||||
sm_write_regs(ssm, REG_SCRAMBLE_DATA_INDEX, 5, buf);
|
sm_write_regs(ssm, dev, REG_SCRAMBLE_DATA_INDEX, 5, buf);
|
||||||
break;
|
break;
|
||||||
case IMAGING_READ_KEY:
|
case IMAGING_READ_KEY:
|
||||||
sm_read_regs(ssm, REG_SCRAMBLE_DATA_KEY, 4);
|
sm_read_regs(ssm, dev, REG_SCRAMBLE_DATA_KEY, 4);
|
||||||
break;
|
break;
|
||||||
case IMAGING_DECODE:
|
case IMAGING_DECODE:
|
||||||
key = urudev->last_reg_rd[0];
|
key = urudev->last_reg_rd[0];
|
||||||
@@ -719,7 +761,7 @@ static void imaging_run_state(struct fpi_ssm *ssm)
|
|||||||
key ^= urudev->img_enc_seed;
|
key ^= urudev->img_enc_seed;
|
||||||
|
|
||||||
fp_dbg("encryption id %02x -> key %08x", img->key_number, key);
|
fp_dbg("encryption id %02x -> key %08x", img->key_number, key);
|
||||||
while (urudev->img_block < array_n_elements(img->block_info) &&
|
while (urudev->img_block < G_N_ELEMENTS(img->block_info) &&
|
||||||
urudev->img_lines_done < img->num_lines) {
|
urudev->img_lines_done < img->num_lines) {
|
||||||
flags = img->block_info[urudev->img_block].flags;
|
flags = img->block_info[urudev->img_block].flags;
|
||||||
num_lines = img->block_info[urudev->img_block].num_lines;
|
num_lines = img->block_info[urudev->img_block].num_lines;
|
||||||
@@ -757,7 +799,7 @@ static void imaging_run_state(struct fpi_ssm *ssm)
|
|||||||
fpimg = fpi_img_new_for_imgdev(dev);
|
fpimg = fpi_img_new_for_imgdev(dev);
|
||||||
|
|
||||||
to = r = 0;
|
to = r = 0;
|
||||||
for (i = 0; i < array_n_elements(img->block_info) && r < img->num_lines; i++) {
|
for (i = 0; i < G_N_ELEMENTS(img->block_info) && r < img->num_lines; i++) {
|
||||||
flags = img->block_info[i].flags;
|
flags = img->block_info[i].flags;
|
||||||
num_lines = img->block_info[i].num_lines;
|
num_lines = img->block_info[i].num_lines;
|
||||||
if (num_lines == 0)
|
if (num_lines == 0)
|
||||||
@@ -782,11 +824,11 @@ static void imaging_run_state(struct fpi_ssm *ssm)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void imaging_complete(struct fpi_ssm *ssm)
|
static void imaging_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = user_data;
|
||||||
struct uru4k_dev *urudev = dev->priv;
|
struct uru4k_dev *urudev = FP_INSTANCE_DATA(_dev);
|
||||||
int r = ssm->error;
|
int r = fpi_ssm_get_error(ssm);
|
||||||
fpi_ssm_free(ssm);
|
fpi_ssm_free(ssm);
|
||||||
|
|
||||||
/* Report error before exiting imaging loop - the error handler
|
/* Report error before exiting imaging loop - the error handler
|
||||||
@@ -795,11 +837,12 @@ static void imaging_complete(struct fpi_ssm *ssm)
|
|||||||
if (r)
|
if (r)
|
||||||
fpi_imgdev_session_error(dev, r);
|
fpi_imgdev_session_error(dev, r);
|
||||||
|
|
||||||
|
/* Freed by callback or cancellation */
|
||||||
|
urudev->img_transfer = NULL;
|
||||||
|
|
||||||
g_free(urudev->img_data);
|
g_free(urudev->img_data);
|
||||||
urudev->img_data = NULL;
|
urudev->img_data = NULL;
|
||||||
|
urudev->img_data_actual_length = 0;
|
||||||
libusb_free_transfer(urudev->img_transfer);
|
|
||||||
urudev->img_transfer = NULL;
|
|
||||||
|
|
||||||
r = execute_state_change(dev);
|
r = execute_state_change(dev);
|
||||||
if (r)
|
if (r)
|
||||||
@@ -832,32 +875,33 @@ enum rebootpwr_states {
|
|||||||
REBOOTPWR_NUM_STATES,
|
REBOOTPWR_NUM_STATES,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void rebootpwr_pause_cb(void *data)
|
static void
|
||||||
|
rebootpwr_pause_cb(struct fp_dev *dev,
|
||||||
|
void *data)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = data;
|
fpi_ssm *ssm = data;
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct uru4k_dev *urudev = FP_INSTANCE_DATA(dev);
|
||||||
struct uru4k_dev *urudev = dev->priv;
|
|
||||||
|
|
||||||
if (!--urudev->rebootpwr_ctr) {
|
if (!--urudev->rebootpwr_ctr) {
|
||||||
fp_err("could not reboot device power");
|
fp_err("could not reboot device power");
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
} else {
|
} else {
|
||||||
fpi_ssm_jump_to_state(ssm, REBOOTPWR_GET_HWSTAT);
|
fpi_ssm_jump_to_state(ssm, REBOOTPWR_GET_HWSTAT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rebootpwr_run_state(struct fpi_ssm *ssm)
|
static void rebootpwr_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = user_data;
|
||||||
struct uru4k_dev *urudev = dev->priv;
|
struct uru4k_dev *urudev = FP_INSTANCE_DATA(_dev);
|
||||||
|
|
||||||
switch (ssm->cur_state) {
|
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||||
case REBOOTPWR_SET_HWSTAT:
|
case REBOOTPWR_SET_HWSTAT:
|
||||||
urudev->rebootpwr_ctr = 100;
|
urudev->rebootpwr_ctr = 100;
|
||||||
sm_set_hwstat(ssm, urudev->last_hwstat & 0xf);
|
sm_set_hwstat(ssm, dev, urudev->last_hwstat & 0xf);
|
||||||
break;
|
break;
|
||||||
case REBOOTPWR_GET_HWSTAT:
|
case REBOOTPWR_GET_HWSTAT:
|
||||||
sm_read_reg(ssm, REG_HWSTAT);
|
sm_read_reg(ssm, dev, REG_HWSTAT);
|
||||||
break;
|
break;
|
||||||
case REBOOTPWR_CHECK_HWSTAT:
|
case REBOOTPWR_CHECK_HWSTAT:
|
||||||
urudev->last_hwstat = urudev->last_reg_rd[0];
|
urudev->last_hwstat = urudev->last_reg_rd[0];
|
||||||
@@ -867,16 +911,16 @@ static void rebootpwr_run_state(struct fpi_ssm *ssm)
|
|||||||
fpi_ssm_next_state(ssm);
|
fpi_ssm_next_state(ssm);
|
||||||
break;
|
break;
|
||||||
case REBOOTPWR_PAUSE:
|
case REBOOTPWR_PAUSE:
|
||||||
if (fpi_timeout_add(10, rebootpwr_pause_cb, ssm) == NULL)
|
if (fpi_timeout_add(10, rebootpwr_pause_cb, _dev, ssm) == NULL)
|
||||||
fpi_ssm_mark_aborted(ssm, -ETIME);
|
fpi_ssm_mark_failed(ssm, -ETIME);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* After messing with the device firmware in it's low-power state, we have to
|
/* After messing with the device firmware in its low-power state, we have to
|
||||||
* power it back up and wait for interrupt notification. It's not quite as easy
|
* power it back up and wait for interrupt notification. It's not quite as easy
|
||||||
* as that: the combination of both modifying firmware *and* doing C-R auth on
|
* as that: the combination of both modifying firmware *and* doing C-R auth on
|
||||||
* my ms fp v2 device causes us not to get to get the 56aa interrupt and
|
* my ms fp v2 device causes us not to get the 56aa interrupt and
|
||||||
* for the hwstat write not to take effect. We have to loop a few times,
|
* for the hwstat write not to take effect. We have to loop a few times,
|
||||||
* authenticating each time, until the device wakes up.
|
* authenticating each time, until the device wakes up.
|
||||||
*
|
*
|
||||||
@@ -909,15 +953,16 @@ enum powerup_states {
|
|||||||
POWERUP_NUM_STATES,
|
POWERUP_NUM_STATES,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void powerup_pause_cb(void *data)
|
static void
|
||||||
|
powerup_pause_cb(struct fp_dev *dev,
|
||||||
|
void *data)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = data;
|
fpi_ssm *ssm = data;
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct uru4k_dev *urudev = FP_INSTANCE_DATA(dev);
|
||||||
struct uru4k_dev *urudev = dev->priv;
|
|
||||||
|
|
||||||
if (!--urudev->powerup_ctr) {
|
if (!--urudev->powerup_ctr) {
|
||||||
fp_err("could not power device up");
|
fp_err("could not power device up");
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
} else if (!urudev->profile->auth_cr) {
|
} else if (!urudev->profile->auth_cr) {
|
||||||
fpi_ssm_jump_to_state(ssm, POWERUP_SET_HWSTAT);
|
fpi_ssm_jump_to_state(ssm, POWERUP_SET_HWSTAT);
|
||||||
} else {
|
} else {
|
||||||
@@ -925,22 +970,22 @@ static void powerup_pause_cb(void *data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void powerup_run_state(struct fpi_ssm *ssm)
|
static void powerup_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = user_data;
|
||||||
struct uru4k_dev *urudev = dev->priv;
|
struct uru4k_dev *urudev = FP_INSTANCE_DATA(_dev);
|
||||||
|
|
||||||
switch (ssm->cur_state) {
|
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||||
case POWERUP_INIT:
|
case POWERUP_INIT:
|
||||||
urudev->powerup_ctr = 100;
|
urudev->powerup_ctr = 100;
|
||||||
urudev->powerup_hwstat = urudev->last_hwstat & 0xf;
|
urudev->powerup_hwstat = urudev->last_hwstat & 0xf;
|
||||||
fpi_ssm_next_state(ssm);
|
fpi_ssm_next_state(ssm);
|
||||||
break;
|
break;
|
||||||
case POWERUP_SET_HWSTAT:
|
case POWERUP_SET_HWSTAT:
|
||||||
sm_set_hwstat(ssm, urudev->powerup_hwstat);
|
sm_set_hwstat(ssm, dev, urudev->powerup_hwstat);
|
||||||
break;
|
break;
|
||||||
case POWERUP_GET_HWSTAT:
|
case POWERUP_GET_HWSTAT:
|
||||||
sm_read_reg(ssm, REG_HWSTAT);
|
sm_read_reg(ssm, dev, REG_HWSTAT);
|
||||||
break;
|
break;
|
||||||
case POWERUP_CHECK_HWSTAT:
|
case POWERUP_CHECK_HWSTAT:
|
||||||
urudev->last_hwstat = urudev->last_reg_rd[0];
|
urudev->last_hwstat = urudev->last_reg_rd[0];
|
||||||
@@ -950,11 +995,11 @@ static void powerup_run_state(struct fpi_ssm *ssm)
|
|||||||
fpi_ssm_next_state(ssm);
|
fpi_ssm_next_state(ssm);
|
||||||
break;
|
break;
|
||||||
case POWERUP_PAUSE:
|
case POWERUP_PAUSE:
|
||||||
if (fpi_timeout_add(10, powerup_pause_cb, ssm) == NULL)
|
if (fpi_timeout_add(10, powerup_pause_cb, _dev, ssm) == NULL)
|
||||||
fpi_ssm_mark_aborted(ssm, -ETIME);
|
fpi_ssm_mark_failed(ssm, -ETIME);
|
||||||
break;
|
break;
|
||||||
case POWERUP_CHALLENGE_RESPONSE:
|
case POWERUP_CHALLENGE_RESPONSE:
|
||||||
sm_do_challenge_response(ssm);
|
sm_do_challenge_response(ssm, dev);
|
||||||
break;
|
break;
|
||||||
case POWERUP_CHALLENGE_RESPONSE_SUCCESS:
|
case POWERUP_CHALLENGE_RESPONSE_SUCCESS:
|
||||||
fpi_ssm_jump_to_state(ssm, POWERUP_SET_HWSTAT);
|
fpi_ssm_jump_to_state(ssm, POWERUP_SET_HWSTAT);
|
||||||
@@ -996,14 +1041,14 @@ enum init_states {
|
|||||||
static void init_scanpwr_irq_cb(struct fp_img_dev *dev, int status,
|
static void init_scanpwr_irq_cb(struct fp_img_dev *dev, int status,
|
||||||
uint16_t type, void *user_data)
|
uint16_t type, void *user_data)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = user_data;
|
fpi_ssm *ssm = user_data;
|
||||||
struct uru4k_dev *urudev = dev->priv;
|
struct uru4k_dev *urudev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
|
||||||
if (status)
|
if (status)
|
||||||
fpi_ssm_mark_aborted(ssm, status);
|
fpi_ssm_mark_failed(ssm, status);
|
||||||
else if (type != IRQDATA_SCANPWR_ON)
|
else if (type != IRQDATA_SCANPWR_ON)
|
||||||
fp_dbg("ignoring interrupt");
|
fp_dbg("ignoring interrupt");
|
||||||
else if (ssm->cur_state != INIT_AWAIT_SCAN_POWER) {
|
else if (fpi_ssm_get_cur_state(ssm) != INIT_AWAIT_SCAN_POWER) {
|
||||||
fp_dbg("early scanpwr interrupt");
|
fp_dbg("early scanpwr interrupt");
|
||||||
urudev->scanpwr_irq_timeouts = -1;
|
urudev->scanpwr_irq_timeouts = -1;
|
||||||
} else {
|
} else {
|
||||||
@@ -1012,11 +1057,12 @@ static void init_scanpwr_irq_cb(struct fp_img_dev *dev, int status,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_scanpwr_timeout(void *user_data)
|
static void
|
||||||
|
init_scanpwr_timeout(struct fp_dev *dev,
|
||||||
|
void *user_data)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = user_data;
|
fpi_ssm *ssm = user_data;
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct uru4k_dev *urudev = FP_INSTANCE_DATA(dev);
|
||||||
struct uru4k_dev *urudev = dev->priv;
|
|
||||||
|
|
||||||
fp_warn("powerup timed out");
|
fp_warn("powerup timed out");
|
||||||
urudev->irq_cb = NULL;
|
urudev->irq_cb = NULL;
|
||||||
@@ -1024,20 +1070,20 @@ static void init_scanpwr_timeout(void *user_data)
|
|||||||
|
|
||||||
if (++urudev->scanpwr_irq_timeouts >= 3) {
|
if (++urudev->scanpwr_irq_timeouts >= 3) {
|
||||||
fp_err("powerup timed out 3 times, giving up");
|
fp_err("powerup timed out 3 times, giving up");
|
||||||
fpi_ssm_mark_aborted(ssm, -ETIMEDOUT);
|
fpi_ssm_mark_failed(ssm, -ETIMEDOUT);
|
||||||
} else {
|
} else {
|
||||||
fpi_ssm_jump_to_state(ssm, INIT_GET_HWSTAT);
|
fpi_ssm_jump_to_state(ssm, INIT_GET_HWSTAT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_run_state(struct fpi_ssm *ssm)
|
static void init_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = user_data;
|
||||||
struct uru4k_dev *urudev = dev->priv;
|
struct uru4k_dev *urudev = FP_INSTANCE_DATA(_dev);
|
||||||
|
|
||||||
switch (ssm->cur_state) {
|
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||||
case INIT_GET_HWSTAT:
|
case INIT_GET_HWSTAT:
|
||||||
sm_read_reg(ssm, REG_HWSTAT);
|
sm_read_reg(ssm, dev, REG_HWSTAT);
|
||||||
break;
|
break;
|
||||||
case INIT_CHECK_HWSTAT_REBOOT:
|
case INIT_CHECK_HWSTAT_REBOOT:
|
||||||
urudev->last_hwstat = urudev->last_reg_rd[0];
|
urudev->last_hwstat = urudev->last_reg_rd[0];
|
||||||
@@ -1047,28 +1093,26 @@ static void init_run_state(struct fpi_ssm *ssm)
|
|||||||
fpi_ssm_jump_to_state(ssm, INIT_CHECK_HWSTAT_POWERDOWN);
|
fpi_ssm_jump_to_state(ssm, INIT_CHECK_HWSTAT_POWERDOWN);
|
||||||
break;
|
break;
|
||||||
case INIT_REBOOT_POWER: ;
|
case INIT_REBOOT_POWER: ;
|
||||||
struct fpi_ssm *rebootsm = fpi_ssm_new(dev->dev, rebootpwr_run_state,
|
fpi_ssm *rebootsm = fpi_ssm_new(FP_DEV(dev), rebootpwr_run_state,
|
||||||
REBOOTPWR_NUM_STATES);
|
REBOOTPWR_NUM_STATES, dev);
|
||||||
rebootsm->priv = dev;
|
|
||||||
fpi_ssm_start_subsm(ssm, rebootsm);
|
fpi_ssm_start_subsm(ssm, rebootsm);
|
||||||
break;
|
break;
|
||||||
case INIT_CHECK_HWSTAT_POWERDOWN:
|
case INIT_CHECK_HWSTAT_POWERDOWN:
|
||||||
if ((urudev->last_hwstat & 0x80) == 0)
|
if ((urudev->last_hwstat & 0x80) == 0)
|
||||||
sm_set_hwstat(ssm, urudev->last_hwstat | 0x80);
|
sm_set_hwstat(ssm, dev, urudev->last_hwstat | 0x80);
|
||||||
else
|
else
|
||||||
fpi_ssm_next_state(ssm);
|
fpi_ssm_next_state(ssm);
|
||||||
break;
|
break;
|
||||||
case INIT_POWERUP: ;
|
case INIT_POWERUP: ;
|
||||||
if (!IRQ_HANDLER_IS_RUNNING(urudev)) {
|
if (!IRQ_HANDLER_IS_RUNNING(urudev)) {
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
urudev->irq_cb_data = ssm;
|
urudev->irq_cb_data = ssm;
|
||||||
urudev->irq_cb = init_scanpwr_irq_cb;
|
urudev->irq_cb = init_scanpwr_irq_cb;
|
||||||
|
|
||||||
struct fpi_ssm *powerupsm = fpi_ssm_new(dev->dev, powerup_run_state,
|
fpi_ssm *powerupsm = fpi_ssm_new(FP_DEV(dev), powerup_run_state,
|
||||||
POWERUP_NUM_STATES);
|
POWERUP_NUM_STATES, dev);
|
||||||
powerupsm->priv = dev;
|
|
||||||
fpi_ssm_start_subsm(ssm, powerupsm);
|
fpi_ssm_start_subsm(ssm, powerupsm);
|
||||||
break;
|
break;
|
||||||
case INIT_AWAIT_SCAN_POWER:
|
case INIT_AWAIT_SCAN_POWER:
|
||||||
@@ -1081,9 +1125,10 @@ static void init_run_state(struct fpi_ssm *ssm)
|
|||||||
* so we include this timeout loop to retry the whole process 3 times
|
* so we include this timeout loop to retry the whole process 3 times
|
||||||
* if we don't get an irq any time soon. */
|
* if we don't get an irq any time soon. */
|
||||||
urudev->scanpwr_irq_timeout = fpi_timeout_add(300,
|
urudev->scanpwr_irq_timeout = fpi_timeout_add(300,
|
||||||
init_scanpwr_timeout, ssm);
|
init_scanpwr_timeout,
|
||||||
|
_dev, ssm);
|
||||||
if (!urudev->scanpwr_irq_timeout) {
|
if (!urudev->scanpwr_irq_timeout) {
|
||||||
fpi_ssm_mark_aborted(ssm, -ETIME);
|
fpi_ssm_mark_failed(ssm, -ETIME);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -1097,7 +1142,7 @@ static void init_run_state(struct fpi_ssm *ssm)
|
|||||||
fpi_ssm_next_state(ssm);
|
fpi_ssm_next_state(ssm);
|
||||||
break;
|
break;
|
||||||
case INIT_GET_VERSION:
|
case INIT_GET_VERSION:
|
||||||
sm_read_regs(ssm, REG_DEVICE_INFO, 16);
|
sm_read_regs(ssm, dev, REG_DEVICE_INFO, 16);
|
||||||
break;
|
break;
|
||||||
case INIT_REPORT_VERSION:
|
case INIT_REPORT_VERSION:
|
||||||
/* Likely hardware revision, and firmware version.
|
/* Likely hardware revision, and firmware version.
|
||||||
@@ -1110,29 +1155,19 @@ static void init_run_state(struct fpi_ssm *ssm)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void activate_initsm_complete(struct fpi_ssm *ssm)
|
static void activate_initsm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = user_data;
|
||||||
int r = ssm->error;
|
int r = fpi_ssm_get_error(ssm);
|
||||||
fpi_ssm_free(ssm);
|
fpi_ssm_free(ssm);
|
||||||
|
|
||||||
if (r) {
|
|
||||||
fpi_imgdev_activate_complete(dev, r);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = execute_state_change(dev);
|
|
||||||
fpi_imgdev_activate_complete(dev, r);
|
fpi_imgdev_activate_complete(dev, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME: having state parameter here is kinda useless, will we ever
|
static int dev_activate(struct fp_img_dev *dev)
|
||||||
* see a scenario where the parameter is useful so early on in the activation
|
|
||||||
* process? asynchronity means that it'll only be used in a later function
|
|
||||||
* call. */
|
|
||||||
static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
|
||||||
{
|
{
|
||||||
struct uru4k_dev *urudev = dev->priv;
|
struct uru4k_dev *urudev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
struct fpi_ssm *ssm;
|
fpi_ssm *ssm;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
r = start_irq_handler(dev);
|
r = start_irq_handler(dev);
|
||||||
@@ -1140,9 +1175,7 @@ static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
|||||||
return r;
|
return r;
|
||||||
|
|
||||||
urudev->scanpwr_irq_timeouts = 0;
|
urudev->scanpwr_irq_timeouts = 0;
|
||||||
urudev->activate_state = state;
|
ssm = fpi_ssm_new(FP_DEV(dev), init_run_state, INIT_NUM_STATES, dev);
|
||||||
ssm = fpi_ssm_new(dev->dev, init_run_state, INIT_NUM_STATES);
|
|
||||||
ssm->priv = dev;
|
|
||||||
fpi_ssm_start(ssm, activate_initsm_complete);
|
fpi_ssm_start(ssm, activate_initsm_complete);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1167,8 +1200,9 @@ static void dev_deactivate(struct fp_img_dev *dev)
|
|||||||
|
|
||||||
static int execute_state_change(struct fp_img_dev *dev)
|
static int execute_state_change(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct uru4k_dev *urudev = dev->priv;
|
struct uru4k_dev *urudev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
struct fpi_ssm *ssm;
|
fpi_ssm *ssm;
|
||||||
|
void *img_data;
|
||||||
|
|
||||||
switch (urudev->activate_state) {
|
switch (urudev->activate_state) {
|
||||||
case IMGDEV_STATE_INACTIVE:
|
case IMGDEV_STATE_INACTIVE:
|
||||||
@@ -1191,12 +1225,18 @@ static int execute_state_change(struct fp_img_dev *dev)
|
|||||||
fp_dbg("starting capture");
|
fp_dbg("starting capture");
|
||||||
urudev->irq_cb = NULL;
|
urudev->irq_cb = NULL;
|
||||||
|
|
||||||
urudev->img_transfer = libusb_alloc_transfer(0);
|
ssm = fpi_ssm_new(FP_DEV(dev), imaging_run_state, IMAGING_NUM_STATES, dev);
|
||||||
urudev->img_data = g_malloc(sizeof(struct uru4k_image));
|
img_data = g_malloc(sizeof(struct uru4k_image));
|
||||||
urudev->img_enc_seed = rand();
|
urudev->img_enc_seed = rand();
|
||||||
|
urudev->img_transfer = fpi_usb_fill_bulk_transfer(FP_DEV(dev),
|
||||||
|
ssm,
|
||||||
|
EP_DATA,
|
||||||
|
img_data,
|
||||||
|
sizeof(struct uru4k_image),
|
||||||
|
image_transfer_cb,
|
||||||
|
NULL,
|
||||||
|
0);
|
||||||
|
|
||||||
ssm = fpi_ssm_new(dev->dev, imaging_run_state, IMAGING_NUM_STATES);
|
|
||||||
ssm->priv = dev;
|
|
||||||
fpi_ssm_start(ssm, imaging_complete);
|
fpi_ssm_start(ssm, imaging_complete);
|
||||||
|
|
||||||
return write_reg(dev, REG_MODE, MODE_CAPTURE,
|
return write_reg(dev, REG_MODE, MODE_CAPTURE,
|
||||||
@@ -1229,7 +1269,7 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
|||||||
int r;
|
int r;
|
||||||
|
|
||||||
/* Find fingerprint interface */
|
/* Find fingerprint interface */
|
||||||
r = libusb_get_config_descriptor(libusb_get_device(dev->udev), 0, &config);
|
r = libusb_get_config_descriptor(libusb_get_device(fpi_dev_get_usb_dev(FP_DEV(dev))), 0, &config);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
fp_err("Failed to get config descriptor");
|
fp_err("Failed to get config descriptor");
|
||||||
return r;
|
return r;
|
||||||
@@ -1283,12 +1323,15 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
|||||||
|
|
||||||
/* Device looks like a supported reader */
|
/* Device looks like a supported reader */
|
||||||
|
|
||||||
r = libusb_claim_interface(dev->udev, iface_desc->bInterfaceNumber);
|
r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), iface_desc->bInterfaceNumber);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
fp_err("interface claim failed");
|
fp_err("interface claim failed: %s", libusb_error_name(r));
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Disable loading p11-kit's user configuration */
|
||||||
|
g_setenv ("P11_KIT_NO_USER_CONFIG", "1", TRUE);
|
||||||
|
|
||||||
/* Initialise NSS early */
|
/* Initialise NSS early */
|
||||||
rv = NSS_NoDB_Init(".");
|
rv = NSS_NoDB_Init(".");
|
||||||
if (rv != SECSuccess) {
|
if (rv != SECSuccess) {
|
||||||
@@ -1297,6 +1340,8 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
urudev = g_malloc0(sizeof(*urudev));
|
urudev = g_malloc0(sizeof(*urudev));
|
||||||
|
fp_dev_set_instance_data(FP_DEV(dev), urudev);
|
||||||
|
|
||||||
urudev->profile = &uru4k_dev_info[driver_data];
|
urudev->profile = &uru4k_dev_info[driver_data];
|
||||||
urudev->interface = iface_desc->bInterfaceNumber;
|
urudev->interface = iface_desc->bInterfaceNumber;
|
||||||
|
|
||||||
@@ -1323,7 +1368,6 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
|||||||
}
|
}
|
||||||
urudev->param = PK11_ParamFromIV(urudev->cipher, NULL);
|
urudev->param = PK11_ParamFromIV(urudev->cipher, NULL);
|
||||||
|
|
||||||
dev->priv = urudev;
|
|
||||||
fpi_imgdev_open_complete(dev, 0);
|
fpi_imgdev_open_complete(dev, 0);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
@@ -1333,14 +1377,14 @@ out:
|
|||||||
|
|
||||||
static void dev_deinit(struct fp_img_dev *dev)
|
static void dev_deinit(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct uru4k_dev *urudev = dev->priv;
|
struct uru4k_dev *urudev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
if (urudev->symkey)
|
if (urudev->symkey)
|
||||||
PK11_FreeSymKey (urudev->symkey);
|
PK11_FreeSymKey (urudev->symkey);
|
||||||
if (urudev->param)
|
if (urudev->param)
|
||||||
SECITEM_FreeItem(urudev->param, PR_TRUE);
|
SECITEM_FreeItem(urudev->param, PR_TRUE);
|
||||||
if (urudev->slot)
|
if (urudev->slot)
|
||||||
PK11_FreeSlot(urudev->slot);
|
PK11_FreeSlot(urudev->slot);
|
||||||
libusb_release_interface(dev->udev, urudev->interface);
|
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), urudev->interface);
|
||||||
g_free(urudev);
|
g_free(urudev);
|
||||||
fpi_imgdev_close_complete(dev);
|
fpi_imgdev_close_complete(dev);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
#define FP_COMPONENT "vcom5s"
|
#define FP_COMPONENT "vcom5s"
|
||||||
|
|
||||||
|
#include "drivers_api.h"
|
||||||
|
|
||||||
/* TODO:
|
/* TODO:
|
||||||
* calibration?
|
* calibration?
|
||||||
* image size: windows gets 300x300 through vpas enrollment util?
|
* image size: windows gets 300x300 through vpas enrollment util?
|
||||||
@@ -26,16 +28,6 @@
|
|||||||
* powerdown? does windows do anything special on exit?
|
* powerdown? does windows do anything special on exit?
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <glib.h>
|
|
||||||
#include <libusb.h>
|
|
||||||
|
|
||||||
#include <fp_internal.h>
|
|
||||||
|
|
||||||
#include "driver_ids.h"
|
|
||||||
|
|
||||||
#define CTRL_IN 0xc0
|
#define CTRL_IN 0xc0
|
||||||
#define CTRL_OUT 0x40
|
#define CTRL_OUT 0x40
|
||||||
#define CTRL_TIMEOUT 1000
|
#define CTRL_TIMEOUT 1000
|
||||||
@@ -82,10 +74,10 @@ enum v5s_cmd {
|
|||||||
|
|
||||||
static void sm_write_reg_cb(struct libusb_transfer *transfer)
|
static void sm_write_reg_cb(struct libusb_transfer *transfer)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
|
|
||||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
|
if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
else
|
else
|
||||||
fpi_ssm_next_state(ssm);
|
fpi_ssm_next_state(ssm);
|
||||||
|
|
||||||
@@ -93,38 +85,35 @@ static void sm_write_reg_cb(struct libusb_transfer *transfer)
|
|||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sm_write_reg(struct fpi_ssm *ssm, unsigned char reg,
|
static void
|
||||||
unsigned char value)
|
sm_write_reg(fpi_ssm *ssm,
|
||||||
|
struct fp_img_dev *dev,
|
||||||
|
unsigned char reg,
|
||||||
|
unsigned char value)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
|
||||||
unsigned char *data;
|
unsigned char *data;
|
||||||
int r;
|
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);
|
data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE);
|
||||||
libusb_fill_control_setup(data, CTRL_OUT, reg, value, 0, 0);
|
libusb_fill_control_setup(data, CTRL_OUT, reg, value, 0, 0);
|
||||||
libusb_fill_control_transfer(transfer, dev->udev, data, sm_write_reg_cb,
|
libusb_fill_control_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), data, sm_write_reg_cb,
|
||||||
ssm, CTRL_TIMEOUT);
|
ssm, CTRL_TIMEOUT);
|
||||||
r = libusb_submit_transfer(transfer);
|
r = libusb_submit_transfer(transfer);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
g_free(data);
|
g_free(data);
|
||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
fpi_ssm_mark_aborted(ssm, r);
|
fpi_ssm_mark_failed(ssm, r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sm_exec_cmd_cb(struct libusb_transfer *transfer)
|
static void sm_exec_cmd_cb(struct libusb_transfer *transfer)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
|
|
||||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
|
if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
else
|
else
|
||||||
fpi_ssm_next_state(ssm);
|
fpi_ssm_next_state(ssm);
|
||||||
|
|
||||||
@@ -132,29 +121,26 @@ static void sm_exec_cmd_cb(struct libusb_transfer *transfer)
|
|||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sm_exec_cmd(struct fpi_ssm *ssm, unsigned char cmd,
|
static void
|
||||||
unsigned char param)
|
sm_exec_cmd(fpi_ssm *ssm,
|
||||||
|
struct fp_img_dev *dev,
|
||||||
|
unsigned char cmd,
|
||||||
|
unsigned char param)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
|
||||||
unsigned char *data;
|
unsigned char *data;
|
||||||
int r;
|
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);
|
data = g_malloc(LIBUSB_CONTROL_SETUP_SIZE);
|
||||||
libusb_fill_control_setup(data, CTRL_IN, cmd, param, 0, 0);
|
libusb_fill_control_setup(data, CTRL_IN, cmd, param, 0, 0);
|
||||||
libusb_fill_control_transfer(transfer, dev->udev, data, sm_exec_cmd_cb,
|
libusb_fill_control_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), data, sm_exec_cmd_cb,
|
||||||
ssm, CTRL_TIMEOUT);
|
ssm, CTRL_TIMEOUT);
|
||||||
r = libusb_submit_transfer(transfer);
|
r = libusb_submit_transfer(transfer);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
g_free(data);
|
g_free(data);
|
||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
fpi_ssm_mark_aborted(ssm, r);
|
fpi_ssm_mark_failed(ssm, r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,16 +181,16 @@ static gboolean finger_is_present(unsigned char *data)
|
|||||||
|
|
||||||
/***** IMAGE ACQUISITION *****/
|
/***** IMAGE ACQUISITION *****/
|
||||||
|
|
||||||
static void capture_iterate(struct fpi_ssm *ssm);
|
static void capture_iterate(fpi_ssm *ssm, struct fp_img_dev *dev);
|
||||||
|
|
||||||
static void capture_cb(struct libusb_transfer *transfer)
|
static void capture_cb(struct libusb_transfer *transfer)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
||||||
struct v5s_dev *vdev = dev->priv;
|
struct v5s_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
|
||||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,47 +205,44 @@ static void capture_cb(struct libusb_transfer *transfer)
|
|||||||
fpi_imgdev_image_captured(dev, img);
|
fpi_imgdev_image_captured(dev, img);
|
||||||
fpi_ssm_next_state(ssm);
|
fpi_ssm_next_state(ssm);
|
||||||
} else {
|
} else {
|
||||||
capture_iterate(ssm);
|
capture_iterate(ssm, dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void capture_iterate(struct fpi_ssm *ssm)
|
static void
|
||||||
|
capture_iterate(fpi_ssm *ssm,
|
||||||
|
struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct v5s_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
struct v5s_dev *vdev = dev->priv;
|
|
||||||
int iteration = vdev->capture_iteration;
|
int iteration = vdev->capture_iteration;
|
||||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
struct libusb_transfer *transfer = fpi_usb_alloc();
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (!transfer) {
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(dev)), EP_IN,
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
libusb_fill_bulk_transfer(transfer, dev->udev, EP_IN,
|
|
||||||
vdev->capture_img->data + (RQ_SIZE * iteration), RQ_SIZE,
|
vdev->capture_img->data + (RQ_SIZE * iteration), RQ_SIZE,
|
||||||
capture_cb, ssm, CTRL_TIMEOUT);
|
capture_cb, ssm, CTRL_TIMEOUT);
|
||||||
transfer->flags = LIBUSB_TRANSFER_SHORT_NOT_OK;
|
transfer->flags = LIBUSB_TRANSFER_SHORT_NOT_OK;
|
||||||
r = libusb_submit_transfer(transfer);
|
r = libusb_submit_transfer(transfer);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
fpi_ssm_mark_aborted(ssm, r);
|
fpi_ssm_mark_failed(ssm, r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void sm_do_capture(struct fpi_ssm *ssm)
|
static void
|
||||||
|
sm_do_capture(fpi_ssm *ssm,
|
||||||
|
struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct v5s_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
struct v5s_dev *vdev = dev->priv;
|
|
||||||
|
|
||||||
fp_dbg("");
|
G_DEBUG_HERE();
|
||||||
vdev->capture_img = fpi_img_new_for_imgdev(dev);
|
vdev->capture_img = fpi_img_new_for_imgdev(dev);
|
||||||
vdev->capture_iteration = 0;
|
vdev->capture_iteration = 0;
|
||||||
capture_iterate(ssm);
|
capture_iterate(ssm, dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
/***** CAPTURE LOOP *****/
|
/***** CAPTURE LOOP *****/
|
||||||
@@ -273,27 +256,27 @@ enum loop_states {
|
|||||||
LOOP_NUM_STATES,
|
LOOP_NUM_STATES,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void loop_run_state(struct fpi_ssm *ssm)
|
static void loop_run_state(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = user_data;
|
||||||
struct v5s_dev *vdev = dev->priv;
|
struct v5s_dev *vdev = FP_INSTANCE_DATA(_dev);
|
||||||
|
|
||||||
switch (ssm->cur_state) {
|
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 (vdev->deactivating) {
|
||||||
fp_dbg("deactivating, marking completed");
|
fp_dbg("deactivating, marking completed");
|
||||||
fpi_ssm_mark_completed(ssm);
|
fpi_ssm_mark_completed(ssm);
|
||||||
} else
|
} else
|
||||||
sm_exec_cmd(ssm, CMD_SCAN, 0x00);
|
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);
|
||||||
@@ -301,11 +284,11 @@ static void loop_run_state(struct fpi_ssm *ssm)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void loopsm_complete(struct fpi_ssm *ssm)
|
static void loopsm_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = user_data;
|
||||||
struct v5s_dev *vdev = dev->priv;
|
struct v5s_dev *vdev = FP_INSTANCE_DATA(_dev);
|
||||||
int r = ssm->error;
|
int r = fpi_ssm_get_error(ssm);
|
||||||
|
|
||||||
fpi_ssm_free(ssm);
|
fpi_ssm_free(ssm);
|
||||||
fp_img_free(vdev->capture_img);
|
fp_img_free(vdev->capture_img);
|
||||||
@@ -319,12 +302,11 @@ static void loopsm_complete(struct fpi_ssm *ssm)
|
|||||||
fpi_imgdev_deactivate_complete(dev);
|
fpi_imgdev_deactivate_complete(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
static int dev_activate(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct v5s_dev *vdev = dev->priv;
|
struct v5s_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
struct fpi_ssm *ssm = fpi_ssm_new(dev->dev, loop_run_state,
|
fpi_ssm *ssm = fpi_ssm_new(FP_DEV(dev), loop_run_state,
|
||||||
LOOP_NUM_STATES);
|
LOOP_NUM_STATES, dev);
|
||||||
ssm->priv = dev;
|
|
||||||
vdev->deactivating = FALSE;
|
vdev->deactivating = FALSE;
|
||||||
fpi_ssm_start(ssm, loopsm_complete);
|
fpi_ssm_start(ssm, loopsm_complete);
|
||||||
vdev->loop_running = TRUE;
|
vdev->loop_running = TRUE;
|
||||||
@@ -334,7 +316,7 @@ static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
|||||||
|
|
||||||
static void dev_deactivate(struct fp_img_dev *dev)
|
static void dev_deactivate(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct v5s_dev *vdev = dev->priv;
|
struct v5s_dev *vdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
if (vdev->loop_running)
|
if (vdev->loop_running)
|
||||||
vdev->deactivating = TRUE;
|
vdev->deactivating = TRUE;
|
||||||
else
|
else
|
||||||
@@ -344,11 +326,14 @@ static void dev_deactivate(struct fp_img_dev *dev)
|
|||||||
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
dev->priv = g_malloc0(sizeof(struct v5s_dev));
|
struct v5s_dev *v5s_dev;
|
||||||
|
|
||||||
r = libusb_claim_interface(dev->udev, 0);
|
v5s_dev = g_malloc0(sizeof(struct v5s_dev));
|
||||||
|
fp_dev_set_instance_data(FP_DEV(dev), v5s_dev);
|
||||||
|
|
||||||
|
r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
fp_err("could not claim interface 0");
|
fp_err("could not claim interface 0: %s", libusb_error_name(r));
|
||||||
|
|
||||||
if (r == 0)
|
if (r == 0)
|
||||||
fpi_imgdev_open_complete(dev, 0);
|
fpi_imgdev_open_complete(dev, 0);
|
||||||
@@ -358,8 +343,10 @@ static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
|
|||||||
|
|
||||||
static void dev_deinit(struct fp_img_dev *dev)
|
static void dev_deinit(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
g_free(dev->priv);
|
struct v5s_dev *v5s_dev;
|
||||||
libusb_release_interface(dev->udev, 0);
|
v5s_dev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
g_free(v5s_dev);
|
||||||
|
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||||
fpi_imgdev_close_complete(dev);
|
fpi_imgdev_close_complete(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
791
libfprint/drivers/vfs0050.c
Normal file
791
libfprint/drivers/vfs0050.c
Normal file
@@ -0,0 +1,791 @@
|
|||||||
|
/*
|
||||||
|
* Validity VFS0050 driver for libfprint
|
||||||
|
* Copyright (C) 2015-2016 Konstantin Semenov <zemen17@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 "vfs0050"
|
||||||
|
|
||||||
|
#include "drivers_api.h"
|
||||||
|
#include "vfs0050.h"
|
||||||
|
|
||||||
|
/* USB functions */
|
||||||
|
|
||||||
|
/* Callback for async_write */
|
||||||
|
static void async_write_callback(struct libusb_transfer *transfer)
|
||||||
|
{
|
||||||
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
|
struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm);
|
||||||
|
|
||||||
|
int transferred = transfer->actual_length, error =
|
||||||
|
transfer->status, len = transfer->length;
|
||||||
|
|
||||||
|
if (error != 0) {
|
||||||
|
fp_err("USB write transfer: %s", libusb_error_name(error));
|
||||||
|
fpi_imgdev_session_error(idev, -EIO);
|
||||||
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transferred != len) {
|
||||||
|
fp_err("Written only %d of %d bytes", transferred, len);
|
||||||
|
fpi_imgdev_session_error(idev, -EIO);
|
||||||
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fpi_ssm_next_state(ssm);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send data to EP1, the only out endpoint */
|
||||||
|
static void
|
||||||
|
async_write(fpi_ssm *ssm,
|
||||||
|
struct fp_img_dev *dev,
|
||||||
|
void *data,
|
||||||
|
int len)
|
||||||
|
{
|
||||||
|
struct libusb_device_handle *usb_dev = fpi_dev_get_usb_dev(FP_DEV(dev));
|
||||||
|
struct vfs_dev_t *vdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
|
||||||
|
vdev->transfer = fpi_usb_alloc();
|
||||||
|
vdev->transfer->flags |= LIBUSB_TRANSFER_FREE_TRANSFER;
|
||||||
|
libusb_fill_bulk_transfer(vdev->transfer, usb_dev, 0x01, data, len,
|
||||||
|
async_write_callback, ssm, VFS_USB_TIMEOUT);
|
||||||
|
libusb_submit_transfer(vdev->transfer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Callback for async_read */
|
||||||
|
static void async_read_callback(struct libusb_transfer *transfer)
|
||||||
|
{
|
||||||
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
|
struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm);
|
||||||
|
|
||||||
|
int transferred = transfer->actual_length, error =
|
||||||
|
transfer->status, len = transfer->length;
|
||||||
|
int ep = transfer->endpoint;
|
||||||
|
|
||||||
|
if (error != 0) {
|
||||||
|
fp_err("USB read transfer on endpoint %d: %s", ep - 0x80,
|
||||||
|
libusb_error_name(error));
|
||||||
|
fpi_imgdev_session_error(idev, -EIO);
|
||||||
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transferred != len) {
|
||||||
|
fp_err("Received %d instead of %d bytes", transferred, len);
|
||||||
|
fpi_imgdev_session_error(idev, -EIO);
|
||||||
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fpi_ssm_next_state(ssm);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Receive data from the given ep and compare with expected */
|
||||||
|
static void
|
||||||
|
async_read(fpi_ssm *ssm,
|
||||||
|
struct fp_img_dev *dev,
|
||||||
|
int ep,
|
||||||
|
void *data,
|
||||||
|
int len)
|
||||||
|
{
|
||||||
|
struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm);
|
||||||
|
struct libusb_device_handle *usb_dev = fpi_dev_get_usb_dev(FP_DEV(idev));
|
||||||
|
struct vfs_dev_t *vdev = FP_INSTANCE_DATA(FP_DEV(idev));
|
||||||
|
|
||||||
|
ep |= LIBUSB_ENDPOINT_IN;
|
||||||
|
|
||||||
|
vdev->transfer = fpi_usb_alloc();
|
||||||
|
vdev->transfer->flags |= LIBUSB_TRANSFER_FREE_TRANSFER;
|
||||||
|
|
||||||
|
/* 0x83 is the only interrupt endpoint */
|
||||||
|
if (ep == EP3_IN)
|
||||||
|
libusb_fill_interrupt_transfer(vdev->transfer, usb_dev, ep, data,
|
||||||
|
len, async_read_callback, ssm,
|
||||||
|
VFS_USB_TIMEOUT);
|
||||||
|
else
|
||||||
|
libusb_fill_bulk_transfer(vdev->transfer, usb_dev, ep, data, len,
|
||||||
|
async_read_callback, ssm,
|
||||||
|
VFS_USB_TIMEOUT);
|
||||||
|
libusb_submit_transfer(vdev->transfer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Callback for async_read */
|
||||||
|
static void async_abort_callback(struct libusb_transfer *transfer)
|
||||||
|
{
|
||||||
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
|
struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm);
|
||||||
|
|
||||||
|
int transferred = transfer->actual_length, error = transfer->status;
|
||||||
|
int ep = transfer->endpoint;
|
||||||
|
|
||||||
|
/* In normal case endpoint is empty */
|
||||||
|
if (error == LIBUSB_TRANSFER_TIMED_OUT) {
|
||||||
|
fpi_ssm_next_state(ssm);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error != 0) {
|
||||||
|
fp_err("USB write transfer: %s", libusb_error_name(error));
|
||||||
|
fpi_imgdev_session_error(idev, -EIO);
|
||||||
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Don't stop process, only print warning */
|
||||||
|
if (transferred > 0)
|
||||||
|
fp_warn("Endpoint %d had extra %d bytes", ep - 0x80,
|
||||||
|
transferred);
|
||||||
|
|
||||||
|
fpi_ssm_jump_to_state(ssm, fpi_ssm_get_cur_state(ssm));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Receive data from the given ep and compare with expected */
|
||||||
|
static void async_abort(fpi_ssm *ssm, int ep)
|
||||||
|
{
|
||||||
|
struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm);
|
||||||
|
struct libusb_device_handle *usb_dev = fpi_dev_get_usb_dev(FP_DEV(idev));
|
||||||
|
struct vfs_dev_t *vdev = FP_INSTANCE_DATA(FP_DEV(idev));
|
||||||
|
|
||||||
|
int len = VFS_USB_BUFFER_SIZE;
|
||||||
|
unsigned char *data = g_malloc(VFS_USB_BUFFER_SIZE);
|
||||||
|
|
||||||
|
ep |= LIBUSB_ENDPOINT_IN;
|
||||||
|
|
||||||
|
vdev->transfer = fpi_usb_alloc();
|
||||||
|
vdev->transfer->flags |=
|
||||||
|
LIBUSB_TRANSFER_FREE_TRANSFER | LIBUSB_TRANSFER_FREE_BUFFER;
|
||||||
|
|
||||||
|
/* 0x83 is the only interrupt endpoint */
|
||||||
|
if (ep == EP3_IN)
|
||||||
|
libusb_fill_interrupt_transfer(vdev->transfer, usb_dev, ep, data,
|
||||||
|
len, async_abort_callback, ssm,
|
||||||
|
VFS_USB_ABORT_TIMEOUT);
|
||||||
|
else
|
||||||
|
libusb_fill_bulk_transfer(vdev->transfer, usb_dev, ep, data, len,
|
||||||
|
async_abort_callback, ssm,
|
||||||
|
VFS_USB_ABORT_TIMEOUT);
|
||||||
|
libusb_submit_transfer(vdev->transfer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Image processing functions */
|
||||||
|
|
||||||
|
/* Pixel getter for fpi_assemble_lines */
|
||||||
|
static unsigned char vfs0050_get_pixel(struct fpi_line_asmbl_ctx *ctx,
|
||||||
|
GSList * line, unsigned int x)
|
||||||
|
{
|
||||||
|
return ((struct vfs_line *)line->data)->data[x];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Deviation getter for fpi_assemble_lines */
|
||||||
|
static int vfs0050_get_difference(struct fpi_line_asmbl_ctx *ctx,
|
||||||
|
GSList * line_list_1, GSList * line_list_2)
|
||||||
|
{
|
||||||
|
struct vfs_line *line1 = line_list_1->data;
|
||||||
|
struct vfs_line *line2 = line_list_2->data;
|
||||||
|
const int shift = (VFS_IMAGE_WIDTH - VFS_NEXT_LINE_WIDTH) / 2 - 1;
|
||||||
|
int res = 0;
|
||||||
|
for (int i = 0; i < VFS_NEXT_LINE_WIDTH; ++i) {
|
||||||
|
int x =
|
||||||
|
(int)line1->next_line_part[i] - (int)line2->data[shift + i];
|
||||||
|
res += x * x;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define VFS_NOISE_THRESHOLD 40
|
||||||
|
|
||||||
|
/* Checks whether line is noise or not using hardware parameters */
|
||||||
|
static char is_noise(struct vfs_line *line)
|
||||||
|
{
|
||||||
|
int val1 = line->noise_hash_1;
|
||||||
|
int val2 = line->noise_hash_2;
|
||||||
|
if (val1 > VFS_NOISE_THRESHOLD
|
||||||
|
&& val1 < 256 - VFS_NOISE_THRESHOLD
|
||||||
|
&& val2 > VFS_NOISE_THRESHOLD && val2 < 256 - VFS_NOISE_THRESHOLD)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parameters for fpi_assemble_lines */
|
||||||
|
static struct fpi_line_asmbl_ctx assembling_ctx = {
|
||||||
|
.line_width = VFS_IMAGE_WIDTH,
|
||||||
|
.max_height = VFS_MAX_HEIGHT,
|
||||||
|
.resolution = 10,
|
||||||
|
.median_filter_size = 25,
|
||||||
|
.max_search_offset = 100,
|
||||||
|
.get_deviation = vfs0050_get_difference,
|
||||||
|
.get_pixel = vfs0050_get_pixel,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Processes image before submitting */
|
||||||
|
static struct fp_img *prepare_image(struct vfs_dev_t *vdev)
|
||||||
|
{
|
||||||
|
int height = vdev->bytes / VFS_LINE_SIZE;
|
||||||
|
|
||||||
|
/* Noise cleaning. IMHO, it works pretty well
|
||||||
|
I've not detected cases when it doesn't work or cuts a part of the finger
|
||||||
|
Noise arises at the end of scan when some water remains on the scanner */
|
||||||
|
while (height > 0) {
|
||||||
|
if (!is_noise(vdev->lines_buffer + height - 1))
|
||||||
|
break;
|
||||||
|
--height;
|
||||||
|
}
|
||||||
|
if (height > VFS_MAX_HEIGHT)
|
||||||
|
height = VFS_MAX_HEIGHT;
|
||||||
|
|
||||||
|
/* If image is not good enough */
|
||||||
|
if (height < VFS_IMAGE_WIDTH)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Building GSList */
|
||||||
|
GSList *lines = NULL;
|
||||||
|
for (int i = height - 1; i >= 0; --i)
|
||||||
|
lines = g_slist_prepend(lines, vdev->lines_buffer + i);
|
||||||
|
|
||||||
|
/* Perform line assembling */
|
||||||
|
struct fp_img *img = fpi_assemble_lines(&assembling_ctx, lines, height);
|
||||||
|
|
||||||
|
g_slist_free(lines);
|
||||||
|
return img;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Processes and submits image after fingerprint received */
|
||||||
|
static void submit_image(struct fp_img_dev *idev)
|
||||||
|
{
|
||||||
|
struct vfs_dev_t *vdev = FP_INSTANCE_DATA(FP_DEV(idev));
|
||||||
|
|
||||||
|
/* We were not asked to submit image actually */
|
||||||
|
if (!vdev->active)
|
||||||
|
return;
|
||||||
|
|
||||||
|
struct fp_img *img = prepare_image(vdev);
|
||||||
|
|
||||||
|
if (!img)
|
||||||
|
fpi_imgdev_abort_scan(idev, FP_VERIFY_RETRY_TOO_SHORT);
|
||||||
|
else
|
||||||
|
fpi_imgdev_image_captured(idev, img);
|
||||||
|
|
||||||
|
/* Finger not on the scanner */
|
||||||
|
fpi_imgdev_report_finger_status(idev, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Proto functions */
|
||||||
|
|
||||||
|
/* SSM loop for clear_ep2 */
|
||||||
|
static void
|
||||||
|
clear_ep2_ssm(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
|
{
|
||||||
|
struct fp_img_dev *idev = user_data;
|
||||||
|
|
||||||
|
short result;
|
||||||
|
char command04 = 0x04;
|
||||||
|
|
||||||
|
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||||
|
case SUBSM1_COMMAND_04:
|
||||||
|
async_write(ssm, idev, &command04, sizeof(command04));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SUBSM1_RETURN_CODE:
|
||||||
|
async_read(ssm, idev, 1, &result, sizeof(result));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SUBSM1_ABORT_2:
|
||||||
|
async_abort(ssm, 2);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
fp_err("Unknown SUBSM1 state");
|
||||||
|
fpi_imgdev_session_error(idev, -EIO);
|
||||||
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send command to clear EP2 */
|
||||||
|
static void
|
||||||
|
clear_ep2(fpi_ssm *ssm,
|
||||||
|
struct fp_img_dev *idev)
|
||||||
|
{
|
||||||
|
fpi_ssm *subsm =
|
||||||
|
fpi_ssm_new(FP_DEV(idev), clear_ep2_ssm, SUBSM1_STATES, idev);
|
||||||
|
fpi_ssm_start_subsm(ssm, subsm);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void send_control_packet_ssm(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
|
{
|
||||||
|
struct fp_img_dev *idev = user_data;
|
||||||
|
struct vfs_dev_t *vdev = FP_INSTANCE_DATA(_dev);
|
||||||
|
|
||||||
|
short result;
|
||||||
|
unsigned char *commit_result = NULL;
|
||||||
|
|
||||||
|
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||||
|
case SUBSM2_SEND_CONTROL:
|
||||||
|
async_write(ssm, idev, vdev->control_packet, VFS_CONTROL_PACKET_SIZE);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SUBSM2_RETURN_CODE:
|
||||||
|
async_read(ssm, idev, 1, &result, sizeof(result));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SUBSM2_SEND_COMMIT:
|
||||||
|
/* next_receive_* packets could be sent only in pair */
|
||||||
|
if (vdev->control_packet == next_receive_1) {
|
||||||
|
vdev->control_packet = next_receive_2;
|
||||||
|
fpi_ssm_jump_to_state(ssm, SUBSM2_SEND_CONTROL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* commit_out in Windows differs in each commit, but I send the same each time */
|
||||||
|
async_write(ssm, idev, commit_out, sizeof(commit_out));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SUBSM2_COMMIT_RESPONSE:
|
||||||
|
commit_result = g_malloc(VFS_COMMIT_RESPONSE_SIZE);
|
||||||
|
async_read(ssm, idev, 1, commit_result, VFS_COMMIT_RESPONSE_SIZE);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SUBSM2_READ_EMPTY_INTERRUPT:
|
||||||
|
/* I don't know how to check result, it could be different */
|
||||||
|
g_free(commit_result);
|
||||||
|
|
||||||
|
async_read(ssm, idev, 3, vdev->interrupt, VFS_INTERRUPT_SIZE);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SUBSM2_ABORT_3:
|
||||||
|
/* Check that interrupt is empty */
|
||||||
|
if (memcmp
|
||||||
|
(vdev->interrupt, empty_interrupt, VFS_INTERRUPT_SIZE)) {
|
||||||
|
fp_err("Unknown SUBSM2 state");
|
||||||
|
fpi_imgdev_session_error(idev, -EIO);
|
||||||
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
async_abort(ssm, 3);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SUBSM2_CLEAR_EP2:
|
||||||
|
/* After turn_on Windows doesn't clear EP2 */
|
||||||
|
if (vdev->control_packet != turn_on)
|
||||||
|
clear_ep2(ssm, idev);
|
||||||
|
else
|
||||||
|
fpi_ssm_next_state(ssm);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
fp_err("Unknown SUBSM2 state");
|
||||||
|
fpi_imgdev_session_error(idev, -EIO);
|
||||||
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send device state control packet */
|
||||||
|
static void
|
||||||
|
send_control_packet(fpi_ssm *ssm,
|
||||||
|
struct fp_img_dev *idev)
|
||||||
|
{
|
||||||
|
fpi_ssm *subsm =
|
||||||
|
fpi_ssm_new(FP_DEV(idev), send_control_packet_ssm, SUBSM2_STATES, idev);
|
||||||
|
fpi_ssm_start_subsm(ssm, subsm);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clears all fprint data */
|
||||||
|
static void clear_data(struct vfs_dev_t *vdev)
|
||||||
|
{
|
||||||
|
g_free(vdev->lines_buffer);
|
||||||
|
vdev->lines_buffer = NULL;
|
||||||
|
vdev->memory = vdev->bytes = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* After receiving interrupt from EP3 */
|
||||||
|
static void interrupt_callback(struct libusb_transfer *transfer)
|
||||||
|
{
|
||||||
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
|
struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm);
|
||||||
|
struct vfs_dev_t *vdev = FP_INSTANCE_DATA(FP_DEV(idev));
|
||||||
|
|
||||||
|
char *interrupt = vdev->interrupt;
|
||||||
|
int error = transfer->status, transferred = transfer->actual_length;
|
||||||
|
|
||||||
|
vdev->wait_interrupt = 0;
|
||||||
|
|
||||||
|
/* When we have cancelled transfer, error is ok actually */
|
||||||
|
if (!vdev->active && error == LIBUSB_TRANSFER_CANCELLED)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (error != 0) {
|
||||||
|
fp_err("USB read interrupt transfer: %s",
|
||||||
|
libusb_error_name(error));
|
||||||
|
fpi_imgdev_session_error(idev, -EIO);
|
||||||
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Interrupt size is VFS_INTERRUPT_SIZE bytes in all known cases */
|
||||||
|
if (transferred != VFS_INTERRUPT_SIZE) {
|
||||||
|
fp_err("Unknown interrupt size %d", transferred);
|
||||||
|
/* Abort ssm */
|
||||||
|
fpi_imgdev_session_error(idev, -EIO);
|
||||||
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Standard interrupts */
|
||||||
|
if (memcmp(interrupt, interrupt1, VFS_INTERRUPT_SIZE) == 0 ||
|
||||||
|
memcmp(interrupt, interrupt2, VFS_INTERRUPT_SIZE) == 0 ||
|
||||||
|
memcmp(interrupt, interrupt3, VFS_INTERRUPT_SIZE) == 0) {
|
||||||
|
/* Go to the next ssm stage */
|
||||||
|
fpi_ssm_next_state(ssm);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* When finger is on the scanner before turn_on */
|
||||||
|
if (interrupt[0] == 0x01) {
|
||||||
|
fp_warn("Finger is already on the scanner");
|
||||||
|
|
||||||
|
/* Go to the next ssm stage */
|
||||||
|
fpi_ssm_next_state(ssm);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unknown interrupt; abort the session */
|
||||||
|
fp_err("Unknown interrupt '%02x:%02x:%02x:%02x:%02x'!",
|
||||||
|
interrupt[0] & 0xff, interrupt[1] & 0xff, interrupt[2] & 0xff,
|
||||||
|
interrupt[3] & 0xff, interrupt[4] & 0xff);
|
||||||
|
|
||||||
|
/* Abort ssm */
|
||||||
|
fpi_imgdev_session_error(idev, -EIO);
|
||||||
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void receive_callback(struct libusb_transfer *transfer)
|
||||||
|
{
|
||||||
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
|
struct fp_img_dev *idev = fpi_ssm_get_user_data(ssm);
|
||||||
|
struct vfs_dev_t *vdev = FP_INSTANCE_DATA(FP_DEV(idev));
|
||||||
|
|
||||||
|
int transferred = transfer->actual_length, error = transfer->status;
|
||||||
|
|
||||||
|
if (error != 0 && error != LIBUSB_TRANSFER_TIMED_OUT) {
|
||||||
|
fp_err("USB read transfer: %s", libusb_error_name(error));
|
||||||
|
|
||||||
|
fpi_imgdev_session_error(idev, -EIO);
|
||||||
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if fingerprint data is over */
|
||||||
|
if (transferred == 0) {
|
||||||
|
fpi_ssm_next_state(ssm);
|
||||||
|
} else {
|
||||||
|
vdev->bytes += transferred;
|
||||||
|
|
||||||
|
/* We need more data */
|
||||||
|
fpi_ssm_jump_to_state(ssm, fpi_ssm_get_cur_state(ssm));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Stub to keep SSM alive when waiting an interrupt */
|
||||||
|
static void
|
||||||
|
wait_interrupt(struct fp_dev *dev,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
fpi_ssm *ssm = data;
|
||||||
|
struct vfs_dev_t *vdev = FP_INSTANCE_DATA(dev);
|
||||||
|
|
||||||
|
/* Keep sleeping while this flag is on */
|
||||||
|
if (vdev->wait_interrupt)
|
||||||
|
fpi_ssm_jump_to_state(ssm, fpi_ssm_get_cur_state(ssm));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SSM stub to prepare device to another scan after orange light was on */
|
||||||
|
static void
|
||||||
|
another_scan(struct fp_dev *dev,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
fpi_ssm *ssm = data;
|
||||||
|
fpi_ssm_jump_to_state(ssm, SSM_TURN_ON);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Main SSM loop */
|
||||||
|
static void activate_ssm(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
|
{
|
||||||
|
struct fp_img_dev *idev = user_data;
|
||||||
|
struct libusb_device_handle *usb_dev = fpi_dev_get_usb_dev(FP_DEV(idev));
|
||||||
|
struct vfs_dev_t *vdev = FP_INSTANCE_DATA(_dev);
|
||||||
|
|
||||||
|
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||||
|
case SSM_INITIAL_ABORT_1:
|
||||||
|
async_abort(ssm, 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SSM_INITIAL_ABORT_2:
|
||||||
|
async_abort(ssm, 2);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SSM_INITIAL_ABORT_3:
|
||||||
|
async_abort(ssm, 3);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SSM_CLEAR_EP2:
|
||||||
|
clear_ep2(ssm, idev);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SSM_TURN_OFF:
|
||||||
|
/* Set control_packet argument */
|
||||||
|
vdev->control_packet = turn_off;
|
||||||
|
|
||||||
|
send_control_packet(ssm, idev);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SSM_TURN_ON:
|
||||||
|
if (!vdev->active) {
|
||||||
|
/* The only correct exit */
|
||||||
|
fpi_ssm_mark_completed(ssm);
|
||||||
|
|
||||||
|
if (vdev->need_report) {
|
||||||
|
fpi_imgdev_deactivate_complete(idev);
|
||||||
|
vdev->need_report = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Set control_packet argument */
|
||||||
|
vdev->control_packet = turn_on;
|
||||||
|
|
||||||
|
send_control_packet(ssm, idev);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SSM_ASK_INTERRUPT:
|
||||||
|
/* Activated, light must be blinking now */
|
||||||
|
|
||||||
|
/* If we first time here, report that activate completed */
|
||||||
|
if (vdev->need_report) {
|
||||||
|
fpi_imgdev_activate_complete(idev, 0);
|
||||||
|
vdev->need_report = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Asynchronously enquire an interrupt */
|
||||||
|
vdev->transfer = fpi_usb_alloc();
|
||||||
|
vdev->transfer->flags |= LIBUSB_TRANSFER_FREE_TRANSFER;
|
||||||
|
libusb_fill_interrupt_transfer(vdev->transfer, usb_dev, 0x83,
|
||||||
|
vdev->interrupt,
|
||||||
|
VFS_INTERRUPT_SIZE,
|
||||||
|
interrupt_callback, ssm, 0);
|
||||||
|
libusb_submit_transfer(vdev->transfer);
|
||||||
|
|
||||||
|
/* This flag could be turned off only in callback function */
|
||||||
|
vdev->wait_interrupt = 1;
|
||||||
|
|
||||||
|
/* I've put it here to be sure that data is cleared */
|
||||||
|
clear_data(vdev);
|
||||||
|
|
||||||
|
fpi_ssm_next_state(ssm);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SSM_WAIT_INTERRUPT:
|
||||||
|
/* Check if user had interrupted the process */
|
||||||
|
if (!vdev->active) {
|
||||||
|
libusb_cancel_transfer(vdev->transfer);
|
||||||
|
fpi_ssm_jump_to_state(ssm, SSM_CLEAR_EP2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vdev->wait_interrupt)
|
||||||
|
fpi_timeout_add(VFS_SSM_TIMEOUT, wait_interrupt, _dev, ssm);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SSM_RECEIVE_FINGER:
|
||||||
|
if (vdev->memory == 0) {
|
||||||
|
/* Initialize fingerprint buffer */
|
||||||
|
g_free(vdev->lines_buffer);
|
||||||
|
vdev->memory = VFS_USB_BUFFER_SIZE;
|
||||||
|
vdev->lines_buffer = g_malloc(vdev->memory);
|
||||||
|
vdev->bytes = 0;
|
||||||
|
|
||||||
|
/* Finger is on the scanner */
|
||||||
|
fpi_imgdev_report_finger_status(idev, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Increase buffer size while it's insufficient */
|
||||||
|
while (vdev->bytes + VFS_USB_BUFFER_SIZE > vdev->memory) {
|
||||||
|
vdev->memory <<= 1;
|
||||||
|
vdev->lines_buffer =
|
||||||
|
(struct vfs_line *)g_realloc(vdev->lines_buffer,
|
||||||
|
vdev->memory);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Receive chunk of data */
|
||||||
|
vdev->transfer = fpi_usb_alloc();
|
||||||
|
vdev->transfer->flags |= LIBUSB_TRANSFER_FREE_TRANSFER;
|
||||||
|
libusb_fill_bulk_transfer(vdev->transfer, usb_dev, 0x82,
|
||||||
|
(void *)vdev->lines_buffer +
|
||||||
|
vdev->bytes, VFS_USB_BUFFER_SIZE,
|
||||||
|
receive_callback, ssm,
|
||||||
|
VFS_USB_TIMEOUT);
|
||||||
|
libusb_submit_transfer(vdev->transfer);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SSM_SUBMIT_IMAGE:
|
||||||
|
submit_image(idev);
|
||||||
|
clear_data(vdev);
|
||||||
|
|
||||||
|
/* Wait for probable vdev->active changing */
|
||||||
|
fpi_timeout_add(VFS_SSM_TIMEOUT, fpi_ssm_next_state_timeout_cb, _dev, ssm);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SSM_NEXT_RECEIVE:
|
||||||
|
if (!vdev->active) {
|
||||||
|
/* It's the last scan */
|
||||||
|
fpi_ssm_jump_to_state(ssm, SSM_CLEAR_EP2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set control_packet argument */
|
||||||
|
vdev->control_packet = next_receive_1;
|
||||||
|
|
||||||
|
send_control_packet(ssm, idev);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SSM_WAIT_ANOTHER_SCAN:
|
||||||
|
/* Orange light is on now */
|
||||||
|
fpi_timeout_add(VFS_SSM_ORANGE_TIMEOUT, another_scan, _dev, ssm);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
fp_err("Unknown state");
|
||||||
|
fpi_imgdev_session_error(idev, -EIO);
|
||||||
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Driver functions */
|
||||||
|
|
||||||
|
/* Callback for dev_activate ssm */
|
||||||
|
static void dev_activate_callback(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
|
{
|
||||||
|
struct vfs_dev_t *vdev = FP_INSTANCE_DATA(_dev);
|
||||||
|
|
||||||
|
vdev->ssm_active = 0;
|
||||||
|
|
||||||
|
fpi_ssm_free(ssm);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Activate device */
|
||||||
|
static int dev_activate(struct fp_img_dev *idev)
|
||||||
|
{
|
||||||
|
struct vfs_dev_t *vdev = FP_INSTANCE_DATA(FP_DEV(idev));
|
||||||
|
|
||||||
|
/* Initialize flags */
|
||||||
|
vdev->active = 1;
|
||||||
|
vdev->need_report = 1;
|
||||||
|
vdev->ssm_active = 1;
|
||||||
|
|
||||||
|
fpi_ssm *ssm = fpi_ssm_new(FP_DEV(idev), activate_ssm, SSM_STATES, idev);
|
||||||
|
fpi_ssm_start(ssm, dev_activate_callback);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Deactivate device */
|
||||||
|
static void dev_deactivate(struct fp_img_dev *idev)
|
||||||
|
{
|
||||||
|
struct vfs_dev_t *vdev = FP_INSTANCE_DATA(FP_DEV(idev));
|
||||||
|
|
||||||
|
if (!vdev->ssm_active) {
|
||||||
|
fpi_imgdev_deactivate_complete(idev);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize flags */
|
||||||
|
vdev->active = 0;
|
||||||
|
vdev->need_report = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Callback for dev_open ssm */
|
||||||
|
static void dev_open_callback(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
|
{
|
||||||
|
/* Notify open complete */
|
||||||
|
fpi_imgdev_open_complete(user_data, 0);
|
||||||
|
fpi_ssm_free(ssm);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Open device */
|
||||||
|
static int dev_open(struct fp_img_dev *idev, unsigned long driver_data)
|
||||||
|
{
|
||||||
|
struct vfs_dev_t *vdev;
|
||||||
|
|
||||||
|
/* Claim usb interface */
|
||||||
|
int error = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(idev)), 0);
|
||||||
|
if (error < 0) {
|
||||||
|
/* Interface not claimed, return error */
|
||||||
|
fp_err("could not claim interface 0");
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize private structure */
|
||||||
|
vdev = g_malloc0(sizeof(struct vfs_dev_t));
|
||||||
|
fp_dev_set_instance_data(FP_DEV(idev), vdev);
|
||||||
|
|
||||||
|
/* Clearing previous device state */
|
||||||
|
fpi_ssm *ssm = fpi_ssm_new(FP_DEV(idev), activate_ssm, SSM_STATES, idev);
|
||||||
|
fpi_ssm_start(ssm, dev_open_callback);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Close device */
|
||||||
|
static void dev_close(struct fp_img_dev *idev)
|
||||||
|
{
|
||||||
|
struct vfs_dev_t *vdev;
|
||||||
|
|
||||||
|
/* Release private structure */
|
||||||
|
vdev = FP_INSTANCE_DATA(FP_DEV(idev));
|
||||||
|
g_free(vdev);
|
||||||
|
|
||||||
|
/* Release usb interface */
|
||||||
|
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(idev)), 0);
|
||||||
|
|
||||||
|
/* Notify close complete */
|
||||||
|
fpi_imgdev_close_complete(idev);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Usb id table of device */
|
||||||
|
static const struct usb_id id_table[] = {
|
||||||
|
{.vendor = 0x138a,.product = 0x0050},
|
||||||
|
{0, 0, 0,},
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Device driver definition */
|
||||||
|
struct fp_img_driver vfs0050_driver = {
|
||||||
|
/* Driver specification */
|
||||||
|
.driver = {
|
||||||
|
.id = VFS0050_ID,
|
||||||
|
.name = FP_COMPONENT,
|
||||||
|
.full_name = "Validity VFS0050",
|
||||||
|
.id_table = id_table,
|
||||||
|
.scan_type = FP_SCAN_TYPE_SWIPE,
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Image specification */
|
||||||
|
.flags = 0,
|
||||||
|
.img_width = VFS_IMAGE_WIDTH,
|
||||||
|
.img_height = -1,
|
||||||
|
.bz3_threshold = 24,
|
||||||
|
|
||||||
|
/* Routine specification */
|
||||||
|
.open = dev_open,
|
||||||
|
.close = dev_close,
|
||||||
|
.activate = dev_activate,
|
||||||
|
.deactivate = dev_deactivate,
|
||||||
|
};
|
||||||
382
libfprint/drivers/vfs0050.h
Normal file
382
libfprint/drivers/vfs0050.h
Normal file
@@ -0,0 +1,382 @@
|
|||||||
|
/*
|
||||||
|
* Validity VFS0050 driver for libfprint
|
||||||
|
* Copyright (C) 2015-2016 Konstantin Semenov <zemen17@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
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Timeout for all send/recv operations, except interrupt waiting and abort */
|
||||||
|
#define VFS_USB_TIMEOUT 100
|
||||||
|
/* Timeout for usb abort */
|
||||||
|
#define VFS_USB_ABORT_TIMEOUT 20
|
||||||
|
/* Default timeout for SSM timers */
|
||||||
|
#define VFS_SSM_TIMEOUT 100
|
||||||
|
/* Timeout for orange light */
|
||||||
|
#define VFS_SSM_ORANGE_TIMEOUT 400
|
||||||
|
/* Buffer size for abort and fprint receiving */
|
||||||
|
#define VFS_USB_BUFFER_SIZE 65536
|
||||||
|
|
||||||
|
/* Line size from scanner including metainformation: line number, narrow stripe from the center, etc */
|
||||||
|
#define VFS_LINE_SIZE 148
|
||||||
|
/* Width of narrow stripe from the center */
|
||||||
|
#define VFS_NEXT_LINE_WIDTH 32
|
||||||
|
/* Image width from scanner */
|
||||||
|
#define VFS_IMAGE_WIDTH 100
|
||||||
|
/* Maximum image height after assembling */
|
||||||
|
#define VFS_MAX_HEIGHT 3000
|
||||||
|
|
||||||
|
/* Size of control packets: turn_on, turn_off, next_receive_* */
|
||||||
|
#define VFS_CONTROL_PACKET_SIZE 125
|
||||||
|
/* Size of result of commit */
|
||||||
|
#define VFS_COMMIT_RESPONSE_SIZE 1106
|
||||||
|
/* Size of interrupt from EP3 */
|
||||||
|
#define VFS_INTERRUPT_SIZE 5
|
||||||
|
/* EP3 endpoint */
|
||||||
|
#define EP3_IN 0x83
|
||||||
|
|
||||||
|
/* Fingerprint horizontal line */
|
||||||
|
struct vfs_line {
|
||||||
|
/* It must be always 0x01 */
|
||||||
|
unsigned char _0x01;
|
||||||
|
/* It must be always 0xfe */
|
||||||
|
unsigned char _0xfe;
|
||||||
|
|
||||||
|
/* line number starting from some number in Little-Endian */
|
||||||
|
unsigned short id;
|
||||||
|
|
||||||
|
/* Some hashes which are useful to detect noise */
|
||||||
|
unsigned char noise_hash_1;
|
||||||
|
unsigned char noise_hash_2;
|
||||||
|
|
||||||
|
/* The first byte of _somedata is always 0x00, the second is strange useless cyclic line number */
|
||||||
|
unsigned short _somedata;
|
||||||
|
|
||||||
|
/* Fingerprint image */
|
||||||
|
unsigned char data[VFS_IMAGE_WIDTH];
|
||||||
|
|
||||||
|
/* Narrow fingerprint part from the center used for variable speed lines assembling */
|
||||||
|
unsigned char next_line_part[VFS_NEXT_LINE_WIDTH];
|
||||||
|
|
||||||
|
/* scan_data is 0xfb except some rare cases, it's skipped */
|
||||||
|
unsigned char scan_data[8];
|
||||||
|
} __attribute__ ((__packed__));
|
||||||
|
|
||||||
|
/* The main driver structure */
|
||||||
|
struct vfs_dev_t {
|
||||||
|
/* One if we were asked to read fingerprint, zero otherwise */
|
||||||
|
char active;
|
||||||
|
|
||||||
|
/* Control packet parameter for send_control_packet */
|
||||||
|
unsigned char *control_packet;
|
||||||
|
|
||||||
|
/* For dev_deactivate to check whether ssm still running or not */
|
||||||
|
char ssm_active;
|
||||||
|
|
||||||
|
/* Current async transfer */
|
||||||
|
struct libusb_transfer *transfer;
|
||||||
|
|
||||||
|
/* Should we call fpi_imgdev_activate_complete or fpi_imgdev_deactivate_complete */
|
||||||
|
char need_report;
|
||||||
|
|
||||||
|
/* Should we wait more for interrupt */
|
||||||
|
char wait_interrupt;
|
||||||
|
|
||||||
|
/* Received fingerprint raw lines */
|
||||||
|
struct vfs_line *lines_buffer;
|
||||||
|
|
||||||
|
/* Current number of received bytes and current memory used by data */
|
||||||
|
int bytes, memory;
|
||||||
|
|
||||||
|
/* USB buffer for fingerprint */
|
||||||
|
char *usb_buffer;
|
||||||
|
|
||||||
|
/* Received interrupt data */
|
||||||
|
unsigned char interrupt[8];
|
||||||
|
};
|
||||||
|
|
||||||
|
/* SSM states for clear_ep2 */
|
||||||
|
enum SUBSM1 {
|
||||||
|
SUBSM1_COMMAND_04,
|
||||||
|
SUBSM1_RETURN_CODE,
|
||||||
|
SUBSM1_ABORT_2,
|
||||||
|
|
||||||
|
SUBSM1_STATES,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* SSM states for control */
|
||||||
|
enum SUBSM2 {
|
||||||
|
SUBSM2_SEND_CONTROL,
|
||||||
|
SUBSM2_RETURN_CODE, /* If next_receive, send another control packet */
|
||||||
|
|
||||||
|
SUBSM2_SEND_COMMIT,
|
||||||
|
SUBSM2_COMMIT_RESPONSE,
|
||||||
|
SUBSM2_READ_EMPTY_INTERRUPT,
|
||||||
|
SUBSM2_ABORT_3,
|
||||||
|
SUBSM2_CLEAR_EP2,
|
||||||
|
|
||||||
|
SUBSM2_STATES,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* SSM states for activate_ssm */
|
||||||
|
enum SSM_STATE {
|
||||||
|
SSM_INITIAL_ABORT_1,
|
||||||
|
SSM_INITIAL_ABORT_2,
|
||||||
|
SSM_INITIAL_ABORT_3,
|
||||||
|
SSM_CLEAR_EP2,
|
||||||
|
SSM_TURN_OFF,
|
||||||
|
|
||||||
|
/* Here the device is turned off; if not active, complete ssm */
|
||||||
|
SSM_TURN_ON,
|
||||||
|
|
||||||
|
SSM_ASK_INTERRUPT,
|
||||||
|
SSM_WAIT_INTERRUPT,
|
||||||
|
|
||||||
|
SSM_RECEIVE_FINGER,
|
||||||
|
SSM_SUBMIT_IMAGE,
|
||||||
|
|
||||||
|
/* If not active, jump to CLEAR_EP2 */
|
||||||
|
SSM_NEXT_RECEIVE,
|
||||||
|
SSM_WAIT_ANOTHER_SCAN,
|
||||||
|
/* Jump to TURN_ON */
|
||||||
|
|
||||||
|
SSM_STATES
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Blocks of data from USB sniffer */
|
||||||
|
|
||||||
|
/* Turns on the light */
|
||||||
|
static unsigned char turn_on[] = {
|
||||||
|
0x39, 0x20, 0xBF, 0x02, 0x00, 0xF4, 0x01, 0x00, 0x00, 0x01, 0xD1, 0x00,
|
||||||
|
0x20, 0xD1, 0xD1, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF4, 0x01, 0x00,
|
||||||
|
0x00, 0x01, 0x00, 0x00,
|
||||||
|
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0xF4, 0x01, 0x00,
|
||||||
|
0x00, 0x02, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0xF4, 0x01, 0x00, 0x00, 0x02, 0xD1, 0x00, 0x20, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Power off */
|
||||||
|
static unsigned char turn_off[] = {
|
||||||
|
0x39, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Turns on orange light */
|
||||||
|
static unsigned char next_receive_1[] = {
|
||||||
|
0x39, 0xB8, 0x0B, 0x00, 0x00, 0xB8, 0x0B, 0x00, 0x00, 0x01, 0xD1, 0x00,
|
||||||
|
0x20, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0xD1, 0xD1, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x01, 0x00, 0x00,
|
||||||
|
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x02, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0xB8, 0x0B, 0x00, 0x00, 0x02, 0xD1, 0x00, 0x20, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Packet directly after next_receive_1 */
|
||||||
|
static unsigned char next_receive_2[] = {
|
||||||
|
0x39, 0xE8, 0x03, 0x00, 0x00, 0xE8, 0x03, 0x00, 0x00, 0x01, 0xD1, 0x00,
|
||||||
|
0x20, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0xD1, 0xD1, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x01, 0x00, 0x00,
|
||||||
|
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x02, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0xE8, 0x03, 0x00, 0x00, 0x02, 0xD1, 0x00, 0x20, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Commit message */
|
||||||
|
static unsigned char commit_out[] = {
|
||||||
|
0x02, 0x94, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x2C, 0x03, 0x00,
|
||||||
|
0x30, 0x1B, 0x00, 0x00,
|
||||||
|
0x00, 0x20, 0x00, 0x08, 0x00, 0x20, 0x03, 0x00, 0x30, 0x3D, 0x10, 0x00,
|
||||||
|
0x00, 0x20, 0x00, 0x08,
|
||||||
|
0x00, 0x18, 0x03, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08,
|
||||||
|
0x00, 0x24, 0x03, 0x00,
|
||||||
|
0x30, 0x08, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x28, 0x03, 0x00,
|
||||||
|
0x30, 0x08, 0x00, 0x00,
|
||||||
|
0x00, 0x20, 0x00, 0x08, 0x00, 0x30, 0x03, 0x00, 0x30, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x20, 0x00, 0x08,
|
||||||
|
0x00, 0x38, 0x03, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08,
|
||||||
|
0x00, 0x3C, 0x03, 0x00,
|
||||||
|
0x30, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x44, 0x03, 0x00,
|
||||||
|
0x30, 0x14, 0x00, 0x00,
|
||||||
|
0x00, 0x20, 0x00, 0x08, 0x00, 0x48, 0x03, 0x00, 0x30, 0x01, 0x04, 0x02,
|
||||||
|
0x00, 0x20, 0x00, 0x08,
|
||||||
|
0x00, 0x4C, 0x03, 0x00, 0x30, 0x01, 0x0C, 0x02, 0x00, 0x20, 0x00, 0x08,
|
||||||
|
0x00, 0x54, 0x03, 0x00,
|
||||||
|
0x30, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x5C, 0x03, 0x00,
|
||||||
|
0x30, 0x90, 0x01, 0x02,
|
||||||
|
0x00, 0x20, 0x00, 0x08, 0x00, 0x60, 0x03, 0x00, 0x30, 0x2C, 0x01, 0x19,
|
||||||
|
0x00, 0x20, 0x00, 0x08,
|
||||||
|
0x00, 0x64, 0x03, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08,
|
||||||
|
0x00, 0x6C, 0x03, 0x00,
|
||||||
|
0x30, 0x1E, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x70, 0x03, 0x00,
|
||||||
|
0x30, 0x21, 0x80, 0x00,
|
||||||
|
0x00, 0x20, 0x00, 0x08, 0x00, 0x78, 0x03, 0x00, 0x30, 0x09, 0x00, 0x02,
|
||||||
|
0x00, 0x20, 0x00, 0x08,
|
||||||
|
0x00, 0x7C, 0x03, 0x00, 0x30, 0x0B, 0x00, 0x19, 0x00, 0x20, 0x00, 0x08,
|
||||||
|
0x00, 0x80, 0x03, 0x00,
|
||||||
|
0x30, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x84, 0x03, 0x00,
|
||||||
|
0x30, 0x3A, 0x00, 0x00,
|
||||||
|
0x00, 0x20, 0x00, 0x08, 0x00, 0x88, 0x03, 0x00, 0x30, 0x14, 0x00, 0x00,
|
||||||
|
0x00, 0x20, 0x00, 0x08,
|
||||||
|
0x00, 0x8C, 0x03, 0x00, 0x30, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08,
|
||||||
|
0x00, 0x90, 0x03, 0x00,
|
||||||
|
0x30, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x94, 0x03, 0x00,
|
||||||
|
0x30, 0x08, 0x00, 0x00,
|
||||||
|
0x00, 0x20, 0x00, 0x08, 0x00, 0x98, 0x03, 0x00, 0x30, 0x00, 0x00, 0xA1,
|
||||||
|
0x01, 0x20, 0x00, 0x08,
|
||||||
|
0x00, 0x9C, 0x03, 0x00, 0x30, 0x00, 0x00, 0xA1, 0x01, 0x20, 0x00, 0x08,
|
||||||
|
0x00, 0xA8, 0x03, 0x00,
|
||||||
|
0x30, 0x64, 0x01, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0xAC, 0x03, 0x00,
|
||||||
|
0x30, 0x64, 0x01, 0x00,
|
||||||
|
0x00, 0x20, 0x00, 0x08, 0x00, 0xB0, 0x03, 0x00, 0x30, 0x00, 0x01, 0x00,
|
||||||
|
0x00, 0x20, 0x00, 0x08,
|
||||||
|
0x00, 0xB4, 0x03, 0x00, 0x30, 0x00, 0x01, 0x00, 0x00, 0x20, 0x00, 0x08,
|
||||||
|
0x00, 0xB8, 0x03, 0x00,
|
||||||
|
0x30, 0x05, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0xBC, 0x03, 0x00,
|
||||||
|
0x30, 0x05, 0x00, 0x00,
|
||||||
|
0x00, 0x20, 0x00, 0x08, 0x00, 0xC0, 0x03, 0x00, 0x30, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x20, 0x00, 0x08,
|
||||||
|
0x00, 0x84, 0x03, 0x00, 0x30, 0x3B, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08,
|
||||||
|
0x00, 0x08, 0x07, 0x00,
|
||||||
|
0x30, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x0C, 0x07, 0x00,
|
||||||
|
0x30, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x20, 0x00, 0x08, 0x00, 0x14, 0x07, 0x00, 0x30, 0x20, 0x00, 0x00,
|
||||||
|
0x00, 0x20, 0x00, 0x08,
|
||||||
|
0x00, 0x1C, 0x07, 0x00, 0x30, 0x1A, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08,
|
||||||
|
0x00, 0x70, 0x0D, 0x00,
|
||||||
|
0x30, 0x01, 0x00, 0x00, 0x00, 0x25, 0x00, 0x28, 0x00, 0x10, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x02, 0x00, 0x90, 0x00, 0x00, 0x00, 0x2B, 0xFF, 0x2B, 0xFF, 0x2B,
|
||||||
|
0xED, 0x00, 0x00, 0x2B,
|
||||||
|
0xFB, 0x00, 0x00, 0x2B, 0xC5, 0x00, 0x00, 0x2B, 0x05, 0x80, 0x70, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x24, 0xD3, 0x2E, 0xC0, 0x2C, 0x3B, 0x08, 0xF0, 0x3B, 0x09, 0x24,
|
||||||
|
0xBB, 0x3B, 0x0B, 0x24,
|
||||||
|
0xAA, 0x3B, 0x1F, 0xF8, 0x00, 0x3B, 0x3F, 0xF0, 0x00, 0x3B, 0x35, 0xC0,
|
||||||
|
0x00, 0x38, 0x80, 0x2C,
|
||||||
|
0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x38, 0x80, 0x2C, 0x70, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0xC0,
|
||||||
|
0x3A, 0x80, 0x2C, 0x70, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x3B, 0x0A, 0x80,
|
||||||
|
0x2E, 0x83, 0x24, 0xDB,
|
||||||
|
0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0xC3, 0x2C, 0x31, 0x83, 0x2C, 0x70,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0xCB, 0x33, 0x1B, 0x83, 0x2C, 0x70, 0x00, 0x00, 0x00, 0x00, 0xCB, 0x31,
|
||||||
|
0x83, 0x2C, 0x70, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0xCB, 0x00, 0x33, 0x1E, 0x83, 0x2E, 0x25, 0xFF, 0xC4,
|
||||||
|
0x00, 0x2F, 0x06, 0x84,
|
||||||
|
0x2E, 0x00, 0x00, 0x10, 0x20, 0x29, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00,
|
||||||
|
0x00, 0x23, 0x00, 0x00,
|
||||||
|
0x00, 0x21, 0x00, 0x10, 0x00, 0x48, 0x03, 0x00, 0x30, 0xFF, 0xF0, 0xFF,
|
||||||
|
0xFF, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x04, 0x00, 0x00, 0x21, 0x00, 0x10, 0x00, 0x4C, 0x03, 0x00,
|
||||||
|
0x30, 0xFF, 0xF0, 0xFF,
|
||||||
|
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x21, 0x00, 0x10,
|
||||||
|
0x00, 0x20, 0x03, 0x00,
|
||||||
|
0x30, 0x7F, 0x00, 0xFC, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x80, 0x10, 0x00,
|
||||||
|
0x00, 0x20, 0x00, 0x08,
|
||||||
|
0x00, 0x24, 0x03, 0x00, 0x30, 0x08, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08,
|
||||||
|
0x00, 0x1C, 0x07, 0x00,
|
||||||
|
0x30, 0x1A, 0x00, 0x00, 0x00, 0x21, 0x00, 0x10, 0x00, 0x20, 0x03, 0x00,
|
||||||
|
0x30, 0xC3, 0xFF, 0xFF,
|
||||||
|
0xFF, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x20, 0x00, 0x08,
|
||||||
|
0x00, 0x80, 0x03, 0x00,
|
||||||
|
0x30, 0x02, 0x00, 0x00, 0x00, 0x24, 0x00, 0x84, 0x00, 0x31, 0x65, 0x77,
|
||||||
|
0x77, 0x77, 0x78, 0x88,
|
||||||
|
0x77, 0x77, 0x76, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x78, 0x77, 0x67,
|
||||||
|
0x66, 0x66, 0x66, 0x66,
|
||||||
|
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x76, 0x67, 0x66, 0x66, 0x66, 0x66,
|
||||||
|
0x66, 0x77, 0x66, 0x66,
|
||||||
|
0x66, 0x66, 0x67, 0x66, 0x66, 0x66, 0x66, 0x66, 0x76, 0x76, 0x66, 0x56,
|
||||||
|
0x66, 0x66, 0x56, 0x55,
|
||||||
|
0x65, 0x66, 0x66, 0x66, 0x65, 0x66, 0x66, 0x55, 0x66, 0x66, 0x65, 0x66,
|
||||||
|
0x76, 0x76, 0x77, 0x77,
|
||||||
|
0x66, 0x66, 0x66, 0x76, 0x67, 0x66, 0x77, 0x67, 0x66, 0x66, 0x66, 0x56,
|
||||||
|
0x65, 0x66, 0x65, 0x66,
|
||||||
|
0x66, 0x55, 0x55, 0x54, 0x55, 0x65, 0x66, 0x66, 0x66, 0x76, 0x77, 0x87,
|
||||||
|
0x88, 0x77, 0x66, 0x66,
|
||||||
|
0x66, 0x66, 0x66, 0x66, 0x66, 0x65, 0x66, 0x55, 0x55, 0x65, 0x56, 0x55,
|
||||||
|
0x55, 0x55, 0x54, 0x45,
|
||||||
|
0x54, 0x55, 0x55, 0x55, 0x66, 0x66, 0x66, 0x66, 0x66, 0x77, 0x77, 0x77,
|
||||||
|
0x66, 0x26, 0x00, 0x28,
|
||||||
|
0x00, 0xFF, 0x00, 0x0F, 0x00, 0xF0, 0xF0, 0x0F, 0x00, 0x20, 0x00, 0x00,
|
||||||
|
0x00, 0x30, 0x01, 0x02,
|
||||||
|
0x00, 0x2C, 0x01, 0x28, 0x00, 0x20, 0x80, 0x00, 0x00, 0x0A, 0x00, 0x02,
|
||||||
|
0x00, 0x0B, 0x00, 0x19,
|
||||||
|
0x00, 0x40, 0x1F, 0x10, 0x27, 0x00, 0x0F, 0x03, 0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Known interrupts */
|
||||||
|
|
||||||
|
static unsigned char empty_interrupt[] = {
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
static unsigned char interrupt1[] = {
|
||||||
|
0x02, 0x00, 0x0E, 0x00, 0xF0,
|
||||||
|
};
|
||||||
|
|
||||||
|
static unsigned char interrupt2[] = {
|
||||||
|
0x02, 0x04, 0x0A, 0x00, 0xF0,
|
||||||
|
};
|
||||||
|
|
||||||
|
static unsigned char interrupt3[] = {
|
||||||
|
0x02, 0x00, 0x0A, 0x00, 0xF0,
|
||||||
|
};
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -21,52 +21,31 @@
|
|||||||
|
|
||||||
#define FP_COMPONENT "vfs301"
|
#define FP_COMPONENT "vfs301"
|
||||||
|
|
||||||
#include <errno.h>
|
#include "drivers_api.h"
|
||||||
#include <signal.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <libusb-1.0/libusb.h>
|
|
||||||
|
|
||||||
#include "vfs301_proto.h"
|
#include "vfs301_proto.h"
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include <fp_internal.h>
|
|
||||||
|
|
||||||
#include "driver_ids.h"
|
|
||||||
|
|
||||||
/************************** GENERIC STUFF *************************************/
|
/************************** GENERIC STUFF *************************************/
|
||||||
|
|
||||||
/* Callback of asynchronous sleep */
|
|
||||||
static void async_sleep_cb(void *data)
|
|
||||||
{
|
|
||||||
struct fpi_ssm *ssm = data;
|
|
||||||
|
|
||||||
fpi_ssm_next_state(ssm);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Submit asynchronous sleep */
|
/* Submit asynchronous sleep */
|
||||||
static void async_sleep(unsigned int msec, struct fpi_ssm *ssm)
|
static void
|
||||||
|
async_sleep(unsigned int msec,
|
||||||
|
fpi_ssm *ssm,
|
||||||
|
struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
|
||||||
struct fpi_timeout *timeout;
|
|
||||||
|
|
||||||
/* Add timeout */
|
/* Add timeout */
|
||||||
timeout = fpi_timeout_add(msec, async_sleep_cb, ssm);
|
if (fpi_timeout_add(msec, fpi_ssm_next_state_timeout_cb, FP_DEV(dev), ssm) == NULL) {
|
||||||
|
|
||||||
if (timeout == NULL) {
|
|
||||||
/* Failed to add timeout */
|
/* Failed to add timeout */
|
||||||
fp_err("failed to add timeout");
|
fp_err("failed to add timeout");
|
||||||
fpi_imgdev_session_error(dev, -ETIME);
|
fpi_imgdev_session_error(dev, -ETIME);
|
||||||
fpi_ssm_mark_aborted(ssm, -ETIME);
|
fpi_ssm_mark_failed(ssm, -ETIME);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int submit_image(struct fpi_ssm *ssm)
|
static int
|
||||||
|
submit_image(fpi_ssm *ssm,
|
||||||
|
struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
vfs301_dev_t *vdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
vfs301_dev_t *vdev = dev->priv;
|
|
||||||
int height;
|
int height;
|
||||||
struct fp_img *img;
|
struct fp_img *img;
|
||||||
|
|
||||||
@@ -92,7 +71,7 @@ static int submit_image(struct fpi_ssm *ssm)
|
|||||||
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);
|
img = fpi_img_realloc(img, img->height * img->width);
|
||||||
fpi_imgdev_image_captured(dev, img);
|
fpi_imgdev_image_captured(dev, img);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@@ -115,24 +94,24 @@ 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(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = user_data;
|
||||||
vfs301_dev_t *vdev = dev->priv;
|
vfs301_dev_t *vdev = FP_INSTANCE_DATA(_dev);
|
||||||
|
|
||||||
switch (ssm->cur_state) {
|
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||||
case M_REQUEST_PRINT:
|
case M_REQUEST_PRINT:
|
||||||
vfs301_proto_request_fingerprint(dev->udev, vdev);
|
vfs301_proto_request_fingerprint(fpi_dev_get_usb_dev(FP_DEV(dev)), vdev);
|
||||||
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);
|
async_sleep(200, ssm, dev);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case M_CHECK_PRINT:
|
case M_CHECK_PRINT:
|
||||||
if (!vfs301_proto_peek_event(dev->udev, vdev))
|
if (!vfs301_proto_peek_event(fpi_dev_get_usb_dev(FP_DEV(dev)), vdev))
|
||||||
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);
|
||||||
@@ -140,19 +119,19 @@ static void m_loop_state(struct fpi_ssm *ssm)
|
|||||||
|
|
||||||
case M_READ_PRINT_START:
|
case M_READ_PRINT_START:
|
||||||
fpi_imgdev_report_finger_status(dev, TRUE);
|
fpi_imgdev_report_finger_status(dev, TRUE);
|
||||||
vfs301_proto_process_event_start(dev->udev, vdev);
|
vfs301_proto_process_event_start(fpi_dev_get_usb_dev(FP_DEV(dev)), vdev);
|
||||||
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);
|
async_sleep(200, ssm, dev);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case M_READ_PRINT_POLL:
|
case M_READ_PRINT_POLL:
|
||||||
{
|
{
|
||||||
int rv = vfs301_proto_process_event_poll(dev->udev, vdev);
|
int rv = vfs301_proto_process_event_poll(fpi_dev_get_usb_dev(FP_DEV(dev)), vdev);
|
||||||
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);
|
||||||
else
|
else
|
||||||
@@ -161,7 +140,7 @@ 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_imgdev_report_finger_status(dev, FALSE);
|
||||||
@@ -173,38 +152,37 @@ static void m_loop_state(struct fpi_ssm *ssm)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Complete loop sequential state machine */
|
/* Complete loop sequential state machine */
|
||||||
static void m_loop_complete(struct fpi_ssm *ssm)
|
static void m_loop_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
/* Free sequential state machine */
|
/* Free sequential state machine */
|
||||||
fpi_ssm_free(ssm);
|
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(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = user_data;
|
||||||
vfs301_dev_t *vdev = dev->priv;
|
vfs301_dev_t *vdev = FP_INSTANCE_DATA(_dev);
|
||||||
|
|
||||||
assert(ssm->cur_state == 0);
|
g_assert(fpi_ssm_get_cur_state(ssm) == 0);
|
||||||
|
|
||||||
vfs301_proto_init(dev->udev, vdev);
|
vfs301_proto_init(fpi_dev_get_usb_dev(FP_DEV(dev)), vdev);
|
||||||
|
|
||||||
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(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = ssm->priv;
|
struct fp_img_dev *dev = user_data;
|
||||||
struct fpi_ssm *ssm_loop;
|
fpi_ssm *ssm_loop;
|
||||||
|
|
||||||
if (!ssm->error) {
|
if (!fpi_ssm_get_error(ssm)) {
|
||||||
/* Notify activate complete */
|
/* Notify activate complete */
|
||||||
fpi_imgdev_activate_complete(dev, 0);
|
fpi_imgdev_activate_complete(dev, 0);
|
||||||
|
|
||||||
/* Start loop ssm */
|
/* Start loop ssm */
|
||||||
ssm_loop = fpi_ssm_new(dev->dev, m_loop_state, M_LOOP_NUM_STATES);
|
ssm_loop = fpi_ssm_new(FP_DEV(dev), m_loop_state, M_LOOP_NUM_STATES, dev);
|
||||||
ssm_loop->priv = dev;
|
|
||||||
fpi_ssm_start(ssm_loop, m_loop_complete);
|
fpi_ssm_start(ssm_loop, m_loop_complete);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,13 +191,12 @@ static void m_init_complete(struct fpi_ssm *ssm)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Activate device */
|
/* Activate device */
|
||||||
static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
static int dev_activate(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm;
|
fpi_ssm *ssm;
|
||||||
|
|
||||||
/* Start init ssm */
|
/* Start init ssm */
|
||||||
ssm = fpi_ssm_new(dev->dev, m_init_state, 1);
|
ssm = fpi_ssm_new(FP_DEV(dev), m_init_state, 1, dev);
|
||||||
ssm->priv = dev;
|
|
||||||
fpi_ssm_start(ssm, m_init_complete);
|
fpi_ssm_start(ssm, m_init_complete);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -228,6 +205,10 @@ static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
|||||||
/* Deactivate device */
|
/* Deactivate device */
|
||||||
static void dev_deactivate(struct fp_img_dev *dev)
|
static void dev_deactivate(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
|
vfs301_dev_t *vdev;
|
||||||
|
|
||||||
|
vdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
vfs301_proto_deinit(fpi_dev_get_usb_dev(FP_DEV(dev)), vdev);
|
||||||
fpi_imgdev_deactivate_complete(dev);
|
fpi_imgdev_deactivate_complete(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,16 +218,16 @@ static int dev_open(struct fp_img_dev *dev, unsigned long driver_data)
|
|||||||
int r;
|
int r;
|
||||||
|
|
||||||
/* Claim usb interface */
|
/* Claim usb interface */
|
||||||
r = libusb_claim_interface(dev->udev, 0);
|
r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
/* Interface not claimed, return error */
|
/* Interface not claimed, return error */
|
||||||
fp_err("could not claim interface 0");
|
fp_err("could not claim interface 0: %s", libusb_error_name(r));
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize private structure */
|
/* Initialize private structure */
|
||||||
vdev = g_malloc0(sizeof(vfs301_dev_t));
|
vdev = g_malloc0(sizeof(vfs301_dev_t));
|
||||||
dev->priv = vdev;
|
fp_dev_set_instance_data(FP_DEV(dev), vdev);
|
||||||
|
|
||||||
vdev->scanline_buf = malloc(0);
|
vdev->scanline_buf = malloc(0);
|
||||||
vdev->scanline_count = 0;
|
vdev->scanline_count = 0;
|
||||||
@@ -259,12 +240,15 @@ static int dev_open(struct fp_img_dev *dev, unsigned long driver_data)
|
|||||||
|
|
||||||
static void dev_close(struct fp_img_dev *dev)
|
static void dev_close(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
|
vfs301_dev_t *vdev;
|
||||||
|
|
||||||
/* Release private structure */
|
/* Release private structure */
|
||||||
free(((vfs301_dev_t*)dev->priv)->scanline_buf);
|
vdev = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
g_free(dev->priv);
|
free(vdev->scanline_buf);
|
||||||
|
g_free(vdev);
|
||||||
|
|
||||||
/* Release usb interface */
|
/* Release usb interface */
|
||||||
libusb_release_interface(dev->udev, 0);
|
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||||
|
|
||||||
/* Notify close complete */
|
/* Notify close complete */
|
||||||
fpi_imgdev_close_complete(dev);
|
fpi_imgdev_close_complete(dev);
|
||||||
|
|||||||
@@ -28,18 +28,15 @@
|
|||||||
* - describe some interesting structures better
|
* - describe some interesting structures better
|
||||||
*/
|
*/
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <signal.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <assert.h>
|
#include <unistd.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <libusb-1.0/libusb.h>
|
#include <glib.h>
|
||||||
|
|
||||||
|
#include "fpi-usb.h"
|
||||||
#include "vfs301_proto.h"
|
#include "vfs301_proto.h"
|
||||||
#include "vfs301_proto_fragments.h"
|
#include "vfs301_proto_fragments.h"
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#define min(a, b) (((a) < (b)) ? (a) : (b))
|
|
||||||
|
|
||||||
/************************** USB STUFF *****************************************/
|
/************************** USB STUFF *****************************************/
|
||||||
|
|
||||||
@@ -51,7 +48,7 @@ static void usb_print_packet(int dir, int rv, const unsigned char *data, int len
|
|||||||
#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, " ");
|
||||||
@@ -68,7 +65,7 @@ static int usb_recv(
|
|||||||
vfs301_dev_t *dev,
|
vfs301_dev_t *dev,
|
||||||
struct libusb_device_handle *devh, unsigned char endpoint, int max_bytes)
|
struct libusb_device_handle *devh, unsigned char endpoint, int max_bytes)
|
||||||
{
|
{
|
||||||
assert(max_bytes <= sizeof(dev->recv_buf));
|
g_assert(max_bytes <= sizeof(dev->recv_buf));
|
||||||
|
|
||||||
int r = libusb_bulk_transfer(
|
int r = libusb_bulk_transfer(
|
||||||
devh, endpoint,
|
devh, endpoint,
|
||||||
@@ -99,7 +96,7 @@ static int usb_send(
|
|||||||
usb_print_packet(1, r, data, length);
|
usb_print_packet(1, r, data, length);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
assert(r == 0);
|
g_assert(r == 0);
|
||||||
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
@@ -131,7 +128,7 @@ static void vfs301_proto_generate_0B(int subtype, unsigned char *data, int *len)
|
|||||||
len++;
|
len++;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
assert(!"unsupported");
|
g_assert_not_reached();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -147,8 +144,8 @@ static void translate_str(const char **srcL, unsigned char *data, int *len)
|
|||||||
while (*srcL != NULL) {
|
while (*srcL != NULL) {
|
||||||
src = *srcL;
|
src = *srcL;
|
||||||
while (*src != '\0') {
|
while (*src != '\0') {
|
||||||
assert(*src != '\0');
|
g_assert(*src != '\0');
|
||||||
assert(*(src +1) != '\0');
|
g_assert(*(src +1) != '\0');
|
||||||
*data = (unsigned char)((HEX_TO_INT(*src) << 4) | (HEX_TO_INT(*(src + 1))));
|
*data = (unsigned char)((HEX_TO_INT(*src) << 4) | (HEX_TO_INT(*(src + 1))));
|
||||||
|
|
||||||
data++;
|
data++;
|
||||||
@@ -193,7 +190,7 @@ 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,
|
||||||
};
|
};
|
||||||
assert((int)subtype <= (int)(sizeof(dataLs) / sizeof(dataLs[0])));
|
g_assert((int)subtype <= (int)(sizeof(dataLs) / sizeof(dataLs[0])));
|
||||||
translate_str(dataLs[subtype - 1], data, len);
|
translate_str(dataLs[subtype - 1], data, len);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -214,10 +211,10 @@ static void vfs301_proto_generate(int type, int subtype, unsigned char *data, in
|
|||||||
translate_str(vfs301_next_scan_template, data, len);
|
translate_str(vfs301_next_scan_template, data, len);
|
||||||
unsigned char *field = data + *len - (sizeof(S4_TAIL) - 1) / 2 - 4;
|
unsigned char *field = data + *len - (sizeof(S4_TAIL) - 1) / 2 - 4;
|
||||||
|
|
||||||
assert(*field == 0xDE);
|
g_assert(*field == 0xDE);
|
||||||
assert(*(field + 1) == 0xAD);
|
g_assert(*(field + 1) == 0xAD);
|
||||||
assert(*(field + 2) == 0xDE);
|
g_assert(*(field + 2) == 0xDE);
|
||||||
assert(*(field + 3) == 0xAD);
|
g_assert(*(field + 3) == 0xAD);
|
||||||
|
|
||||||
*field = (unsigned char)((subtype >> 8) & 0xFF);
|
*field = (unsigned char)((subtype >> 8) & 0xFF);
|
||||||
*(field + 1) = (unsigned char)(subtype & 0xFF);
|
*(field + 1) = (unsigned char)(subtype & 0xFF);
|
||||||
@@ -225,15 +222,15 @@ static void vfs301_proto_generate(int type, int subtype, unsigned char *data, in
|
|||||||
*(field + 3) = *(field + 1);
|
*(field + 3) = *(field + 1);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
assert(0);
|
g_assert(0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x06:
|
case 0x06:
|
||||||
assert(!"Not generated");
|
g_assert_not_reached();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
assert(!"Unknown message type");
|
g_assert_not_reached();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -296,7 +293,7 @@ void vfs301_extract_image(
|
|||||||
int last_line;
|
int last_line;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
assert(vfs->scanline_count >= 1);
|
g_assert(vfs->scanline_count >= 1);
|
||||||
|
|
||||||
*output_height = 1;
|
*output_height = 1;
|
||||||
memcpy(output, scanlines, VFS301_FP_OUTPUT_WIDTH);
|
memcpy(output, scanlines, VFS301_FP_OUTPUT_WIDTH);
|
||||||
@@ -344,7 +341,7 @@ static int img_process_data(
|
|||||||
}
|
}
|
||||||
|
|
||||||
dev->scanline_buf = realloc(dev->scanline_buf, dev->scanline_count * VFS301_FP_OUTPUT_WIDTH);
|
dev->scanline_buf = realloc(dev->scanline_buf, dev->scanline_count * VFS301_FP_OUTPUT_WIDTH);
|
||||||
assert(dev->scanline_buf != NULL);
|
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;
|
||||||
@@ -391,7 +388,7 @@ static int vfs301_proto_process_data(int first_block, vfs301_dev_t *dev)
|
|||||||
int len = dev->recv_len;
|
int len = dev->recv_len;
|
||||||
|
|
||||||
if (first_block) {
|
if (first_block) {
|
||||||
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--) {
|
||||||
@@ -417,14 +414,14 @@ int vfs301_proto_peek_event(
|
|||||||
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);
|
||||||
assert(USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 7) == 0);
|
g_assert(USB_RECV(VFS301_RECEIVE_ENDPOINT_CTRL, 7) == 0);
|
||||||
|
|
||||||
if (memcmp(dev->recv_buf, no_event, sizeof(no_event)) == 0) {
|
if (memcmp(dev->recv_buf, 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(dev->recv_buf, got_event, sizeof(no_event)) == 0) {
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
assert(!"unexpected reply to wait");
|
g_assert_not_reached();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -502,12 +499,7 @@ 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_alloc();
|
||||||
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;
|
dev->recv_exp_amt = VFS301_FP_RECV_LEN_1;
|
||||||
|
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ typedef struct {
|
|||||||
|
|
||||||
unsigned char scan[VFS301_FP_WIDTH];
|
unsigned char scan[VFS301_FP_WIDTH];
|
||||||
|
|
||||||
/* A offseted, stretched, inverted copy of scan... probably could
|
/* A offsetted, stretched, inverted copy of scan... probably could
|
||||||
* serve finger motion speed detection?
|
* serve finger motion speed detection?
|
||||||
* Seems to be subdivided to some 10B + 53B + 1B blocks */
|
* Seems to be subdivided to some 10B + 53B + 1B blocks */
|
||||||
unsigned char mirror[64];
|
unsigned char mirror[64];
|
||||||
|
|||||||
@@ -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?
|
||||||
|
|||||||
@@ -18,13 +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
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include "drivers_api.h"
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <libusb.h>
|
|
||||||
#include <fp_internal.h>
|
|
||||||
#include "driver_ids.h"
|
|
||||||
|
|
||||||
#include "vfs5011_proto.h"
|
#include "vfs5011_proto.h"
|
||||||
|
|
||||||
/* =================== sync/async USB transfer sequence ==================== */
|
/* =================== sync/async USB transfer sequence ==================== */
|
||||||
@@ -77,24 +71,26 @@ struct usbexchange_data {
|
|||||||
int timeout;
|
int timeout;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void start_scan(struct fp_img_dev *dev);
|
||||||
|
|
||||||
static void async_send_cb(struct libusb_transfer *transfer)
|
static void async_send_cb(struct libusb_transfer *transfer)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
struct usbexchange_data *data = (struct usbexchange_data *)ssm->priv;
|
struct usbexchange_data *data = fpi_ssm_get_user_data(ssm);
|
||||||
struct usb_action *action;
|
struct usb_action *action;
|
||||||
|
|
||||||
if (ssm->cur_state >= data->stepcount) {
|
if (fpi_ssm_get_cur_state(ssm) >= data->stepcount) {
|
||||||
fp_err("Radiation detected!");
|
fp_err("Radiation detected!");
|
||||||
fpi_imgdev_session_error(data->device, -EINVAL);
|
fpi_imgdev_session_error(data->device, -EINVAL);
|
||||||
fpi_ssm_mark_aborted(ssm, -EINVAL);
|
fpi_ssm_mark_failed(ssm, -EINVAL);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
action = &data->actions[ssm->cur_state];
|
action = &data->actions[fpi_ssm_get_cur_state(ssm)];
|
||||||
if (action->type != ACTION_SEND) {
|
if (action->type != ACTION_SEND) {
|
||||||
fp_err("Radiation detected!");
|
fp_err("Radiation detected!");
|
||||||
fpi_imgdev_session_error(data->device, -EINVAL);
|
fpi_imgdev_session_error(data->device, -EINVAL);
|
||||||
fpi_ssm_mark_aborted(ssm, -EINVAL);
|
fpi_ssm_mark_failed(ssm, -EINVAL);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,7 +98,7 @@ static void async_send_cb(struct libusb_transfer *transfer)
|
|||||||
/* Transfer not completed, return IO error */
|
/* Transfer not completed, return IO error */
|
||||||
fp_err("transfer not completed, status = %d", transfer->status);
|
fp_err("transfer not completed, status = %d", transfer->status);
|
||||||
fpi_imgdev_session_error(data->device, -EIO);
|
fpi_imgdev_session_error(data->device, -EIO);
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (transfer->length != transfer->actual_length) {
|
if (transfer->length != transfer->actual_length) {
|
||||||
@@ -110,7 +106,7 @@ static void async_send_cb(struct libusb_transfer *transfer)
|
|||||||
fp_err("length mismatch, got %d, expected %d",
|
fp_err("length mismatch, got %d, expected %d",
|
||||||
transfer->actual_length, transfer->length);
|
transfer->actual_length, transfer->length);
|
||||||
fpi_imgdev_session_error(data->device, -EIO);
|
fpi_imgdev_session_error(data->device, -EIO);
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,30 +119,30 @@ out:
|
|||||||
|
|
||||||
static void async_recv_cb(struct libusb_transfer *transfer)
|
static void async_recv_cb(struct libusb_transfer *transfer)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = transfer->user_data;
|
fpi_ssm *ssm = transfer->user_data;
|
||||||
struct usbexchange_data *data = (struct usbexchange_data *)ssm->priv;
|
struct usbexchange_data *data = fpi_ssm_get_user_data(ssm);
|
||||||
struct usb_action *action;
|
struct usb_action *action;
|
||||||
|
|
||||||
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
|
||||||
/* Transfer not completed, return IO error */
|
/* Transfer not completed, return IO error */
|
||||||
fp_err("transfer not completed, status = %d", transfer->status);
|
fp_err("transfer not completed, status = %d", transfer->status);
|
||||||
fpi_imgdev_session_error(data->device, -EIO);
|
fpi_imgdev_session_error(data->device, -EIO);
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ssm->cur_state >= data->stepcount) {
|
if (fpi_ssm_get_cur_state(ssm) >= data->stepcount) {
|
||||||
fp_err("Radiation detected!");
|
fp_err("Radiation detected!");
|
||||||
fpi_imgdev_session_error(data->device, -EINVAL);
|
fpi_imgdev_session_error(data->device, -EINVAL);
|
||||||
fpi_ssm_mark_aborted(ssm, -EINVAL);
|
fpi_ssm_mark_failed(ssm, -EINVAL);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
action = &data->actions[ssm->cur_state];
|
action = &data->actions[fpi_ssm_get_cur_state(ssm)];
|
||||||
if (action->type != ACTION_RECEIVE) {
|
if (action->type != ACTION_RECEIVE) {
|
||||||
fp_err("Radiation detected!");
|
fp_err("Radiation detected!");
|
||||||
fpi_imgdev_session_error(data->device, -EINVAL);
|
fpi_imgdev_session_error(data->device, -EINVAL);
|
||||||
fpi_ssm_mark_aborted(ssm, -EINVAL);
|
fpi_ssm_mark_failed(ssm, -EINVAL);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,14 +152,14 @@ static void async_recv_cb(struct libusb_transfer *transfer)
|
|||||||
transfer->actual_length,
|
transfer->actual_length,
|
||||||
action->correct_reply_size);
|
action->correct_reply_size);
|
||||||
fpi_imgdev_session_error(data->device, -EIO);
|
fpi_imgdev_session_error(data->device, -EIO);
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (memcmp(transfer->buffer, action->data,
|
if (memcmp(transfer->buffer, action->data,
|
||||||
action->correct_reply_size) != 0) {
|
action->correct_reply_size) != 0) {
|
||||||
fp_dbg("Wrong reply:");
|
fp_dbg("Wrong reply:");
|
||||||
fpi_imgdev_session_error(data->device, -EIO);
|
fpi_imgdev_session_error(data->device, -EIO);
|
||||||
fpi_ssm_mark_aborted(ssm, -EIO);
|
fpi_ssm_mark_failed(ssm, -EIO);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
@@ -175,32 +171,26 @@ out:
|
|||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void usbexchange_loop(struct fpi_ssm *ssm)
|
static void usbexchange_loop(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct usbexchange_data *data = (struct usbexchange_data *)ssm->priv;
|
struct usbexchange_data *data = user_data;
|
||||||
if (ssm->cur_state >= data->stepcount) {
|
if (fpi_ssm_get_cur_state(ssm) >= data->stepcount) {
|
||||||
fp_err("Bug detected: state %d out of range, only %d steps",
|
fp_err("Bug detected: state %d out of range, only %d steps",
|
||||||
ssm->cur_state, data->stepcount);
|
fpi_ssm_get_cur_state(ssm), data->stepcount);
|
||||||
fpi_imgdev_session_error(data->device, -EINVAL);
|
fpi_imgdev_session_error(data->device, -EINVAL);
|
||||||
fpi_ssm_mark_aborted(ssm, -EINVAL);
|
fpi_ssm_mark_failed(ssm, -EINVAL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct usb_action *action = &data->actions[ssm->cur_state];
|
struct usb_action *action = &data->actions[fpi_ssm_get_cur_state(ssm)];
|
||||||
struct libusb_transfer *transfer;
|
struct libusb_transfer *transfer;
|
||||||
int ret = -EINVAL;
|
int ret = -EINVAL;
|
||||||
|
|
||||||
switch (action->type) {
|
switch (action->type) {
|
||||||
case ACTION_SEND:
|
case ACTION_SEND:
|
||||||
fp_dbg("Sending %s", action->name);
|
fp_dbg("Sending %s", action->name);
|
||||||
transfer = libusb_alloc_transfer(0);
|
transfer = fpi_usb_alloc();
|
||||||
if (transfer == NULL) {
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(data->device)),
|
||||||
fp_err("Failed to allocate transfer");
|
|
||||||
fpi_imgdev_session_error(data->device, -ENOMEM);
|
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
libusb_fill_bulk_transfer(transfer, data->device->udev,
|
|
||||||
action->endpoint, action->data,
|
action->endpoint, action->data,
|
||||||
action->size, async_send_cb, ssm,
|
action->size, async_send_cb, ssm,
|
||||||
data->timeout);
|
data->timeout);
|
||||||
@@ -209,14 +199,8 @@ static void usbexchange_loop(struct fpi_ssm *ssm)
|
|||||||
|
|
||||||
case ACTION_RECEIVE:
|
case ACTION_RECEIVE:
|
||||||
fp_dbg("Receiving %d bytes", action->size);
|
fp_dbg("Receiving %d bytes", action->size);
|
||||||
transfer = libusb_alloc_transfer(0);
|
transfer = fpi_usb_alloc();
|
||||||
if (transfer == NULL) {
|
libusb_fill_bulk_transfer(transfer, fpi_dev_get_usb_dev(FP_DEV(data->device)),
|
||||||
fp_err("Failed to allocate transfer");
|
|
||||||
fpi_imgdev_session_error(data->device, -ENOMEM);
|
|
||||||
fpi_ssm_mark_aborted(ssm, -ENOMEM);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
libusb_fill_bulk_transfer(transfer, data->device->udev,
|
|
||||||
action->endpoint, data->receive_buf,
|
action->endpoint, data->receive_buf,
|
||||||
action->size, async_recv_cb, ssm,
|
action->size, async_recv_cb, ssm,
|
||||||
data->timeout);
|
data->timeout);
|
||||||
@@ -226,66 +210,39 @@ static void usbexchange_loop(struct fpi_ssm *ssm)
|
|||||||
default:
|
default:
|
||||||
fp_err("Bug detected: invalid action %d", action->type);
|
fp_err("Bug detected: invalid action %d", action->type);
|
||||||
fpi_imgdev_session_error(data->device, -EINVAL);
|
fpi_imgdev_session_error(data->device, -EINVAL);
|
||||||
fpi_ssm_mark_aborted(ssm, -EINVAL);
|
fpi_ssm_mark_failed(ssm, -EINVAL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
fp_err("USB transfer error: %s", strerror(ret));
|
fp_err("USB transfer error: %s", strerror(ret));
|
||||||
fpi_imgdev_session_error(data->device, ret);
|
fpi_imgdev_session_error(data->device, ret);
|
||||||
fpi_ssm_mark_aborted(ssm, ret);
|
fpi_ssm_mark_failed(ssm, ret);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void usb_exchange_async(struct fpi_ssm *ssm,
|
static void usb_exchange_async(fpi_ssm *ssm,
|
||||||
struct usbexchange_data *data)
|
struct usbexchange_data *data)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *subsm = fpi_ssm_new(data->device->dev,
|
fpi_ssm *subsm = fpi_ssm_new(FP_DEV(data->device),
|
||||||
usbexchange_loop,
|
usbexchange_loop,
|
||||||
data->stepcount);
|
data->stepcount,
|
||||||
subsm->priv = data;
|
data);
|
||||||
fpi_ssm_start_subsm(ssm, subsm);
|
fpi_ssm_start_subsm(ssm, subsm);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ====================== utils ======================= */
|
/* ====================== utils ======================= */
|
||||||
|
|
||||||
#if VFS5011_LINE_SIZE > INT_MAX/(256*256)
|
|
||||||
#error We might get integer overflow while computing standard deviation!
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Calculade squared standand deviation */
|
|
||||||
static int get_deviation(unsigned char *buf, int size)
|
|
||||||
{
|
|
||||||
int res = 0, mean = 0, i;
|
|
||||||
for (i = 0; i < size; i++)
|
|
||||||
mean += buf[i];
|
|
||||||
|
|
||||||
mean /= size;
|
|
||||||
|
|
||||||
for (i = 0; i < size; i++) {
|
|
||||||
int dev = (int)buf[i] - mean;
|
|
||||||
res += dev*dev;
|
|
||||||
}
|
|
||||||
|
|
||||||
return res / size;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Calculate mean square difference of two lines */
|
|
||||||
static int get_diff_norm(unsigned char *buf1, unsigned char *buf2, int size)
|
|
||||||
{
|
|
||||||
int res = 0, i;
|
|
||||||
for (i = 0; i < size; i++) {
|
|
||||||
int dev = (int)buf1[i] - (int)buf2[i];
|
|
||||||
res += dev*dev;
|
|
||||||
}
|
|
||||||
|
|
||||||
return res / size;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Calculade squared standand deviation of sum of two lines */
|
/* Calculade squared standand deviation of sum of two lines */
|
||||||
static int get_deviation2(unsigned char *buf1, unsigned char *buf2, int size)
|
static int vfs5011_get_deviation2(struct fpi_line_asmbl_ctx *ctx, GSList *row1, GSList *row2)
|
||||||
{
|
{
|
||||||
|
unsigned char *buf1, *buf2;
|
||||||
int res = 0, mean = 0, i;
|
int res = 0, mean = 0, i;
|
||||||
|
const int size = 64;
|
||||||
|
|
||||||
|
buf1 = row1->data + 56;
|
||||||
|
buf2 = row2->data + 168;
|
||||||
|
|
||||||
for (i = 0; i < size; i++)
|
for (i = 0; i < size; i++)
|
||||||
mean += (int)buf1[i] + (int)buf2[i];
|
mean += (int)buf1[i] + (int)buf2[i];
|
||||||
|
|
||||||
@@ -299,121 +256,13 @@ static int get_deviation2(unsigned char *buf1, unsigned char *buf2, int size)
|
|||||||
return res / size;
|
return res / size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmpint(const void *p1, const void *p2, gpointer data)
|
static unsigned char vfs5011_get_pixel(struct fpi_line_asmbl_ctx *ctx,
|
||||||
|
GSList *row,
|
||||||
|
unsigned x)
|
||||||
{
|
{
|
||||||
int a = *((int *)p1);
|
unsigned char *data = row->data + 8;
|
||||||
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)
|
return data[x];
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
void interpolate_lines(unsigned char *line1, float y1, unsigned char *line2,
|
|
||||||
float y2, unsigned char *output, float yi, int size)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < size; i++)
|
|
||||||
output[i] = (float)line1[i]
|
|
||||||
+ (yi-y1)/(y2-y1)*(line2[i]-line1[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
int min(int a, int b) {return (a < b) ? a : b; }
|
|
||||||
|
|
||||||
/* Rescale image to account for variable swiping speed */
|
|
||||||
int vfs5011_rescale_image(unsigned char *image, int input_lines,
|
|
||||||
unsigned char *output, int max_output_lines)
|
|
||||||
{
|
|
||||||
/* Number of output lines per distance between two scanners */
|
|
||||||
enum {
|
|
||||||
RESOLUTION = 10,
|
|
||||||
MEDIAN_FILTER_SIZE = 13,
|
|
||||||
MAX_OFFSET = 10,
|
|
||||||
GOOD_OFFSETS_CRITERION = 20,
|
|
||||||
GOOD_OFFSETS_THRESHOLD = 3
|
|
||||||
};
|
|
||||||
int i;
|
|
||||||
float y = 0.0;
|
|
||||||
int line_ind = 0;
|
|
||||||
int *offsets = (int *)g_malloc0(input_lines * sizeof(int));
|
|
||||||
#ifdef ENABLE_DEBUG_LOGGING
|
|
||||||
gint64 start_time = g_get_real_time();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for (i = 0; i < input_lines-1; i += 2) {
|
|
||||||
int bestmatch = i;
|
|
||||||
int bestdiff = 0;
|
|
||||||
int j;
|
|
||||||
|
|
||||||
int firstrow, lastrow;
|
|
||||||
firstrow = i+1;
|
|
||||||
lastrow = min(i + MAX_OFFSET, input_lines-1);
|
|
||||||
|
|
||||||
for (j = firstrow; j <= lastrow; j++) {
|
|
||||||
int diff = get_deviation2(
|
|
||||||
image + i*VFS5011_LINE_SIZE + 56,
|
|
||||||
image + j*VFS5011_LINE_SIZE + 168,
|
|
||||||
64);
|
|
||||||
if ((j == firstrow) || (diff < bestdiff)) {
|
|
||||||
bestdiff = diff;
|
|
||||||
bestmatch = j;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
offsets[i/2] = bestmatch - i;
|
|
||||||
fp_dbg("offsets: %llu - %d", start_time, offsets[i/2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
median_filter(offsets, input_lines-1, MEDIAN_FILTER_SIZE);
|
|
||||||
|
|
||||||
fp_dbg("offsets_filtered: %llu", g_get_real_time());
|
|
||||||
for (i = 0; i <= input_lines/2-1; i++)
|
|
||||||
fp_dbg("%d", offsets[i]);
|
|
||||||
for (i = 0; i < input_lines-1; i++) {
|
|
||||||
int offset = offsets[i/2];
|
|
||||||
if (offset > 0) {
|
|
||||||
float ynext = y + (float)RESOLUTION / offset;
|
|
||||||
while (line_ind < ynext) {
|
|
||||||
if (line_ind > max_output_lines-1) {
|
|
||||||
g_free(offsets);
|
|
||||||
return line_ind;
|
|
||||||
}
|
|
||||||
interpolate_lines(
|
|
||||||
image + i*VFS5011_LINE_SIZE + 8, y,
|
|
||||||
image + (i+1)*VFS5011_LINE_SIZE + 8,
|
|
||||||
ynext,
|
|
||||||
output + line_ind*VFS5011_IMAGE_WIDTH,
|
|
||||||
line_ind,
|
|
||||||
VFS5011_IMAGE_WIDTH);
|
|
||||||
line_ind++;
|
|
||||||
}
|
|
||||||
y = ynext;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
g_free(offsets);
|
|
||||||
return line_ind;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ====================== main stuff ======================= */
|
/* ====================== main stuff ======================= */
|
||||||
@@ -424,18 +273,29 @@ enum {
|
|||||||
MAX_CAPTURE_LINES = 100000,
|
MAX_CAPTURE_LINES = 100000,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct fpi_line_asmbl_ctx assembling_ctx = {
|
||||||
|
.line_width = VFS5011_IMAGE_WIDTH,
|
||||||
|
.max_height = MAXLINES,
|
||||||
|
.resolution = 10,
|
||||||
|
.median_filter_size = 25,
|
||||||
|
.max_search_offset = 30,
|
||||||
|
.get_deviation = vfs5011_get_deviation2,
|
||||||
|
.get_pixel = vfs5011_get_pixel,
|
||||||
|
};
|
||||||
|
|
||||||
struct vfs5011_data {
|
struct vfs5011_data {
|
||||||
unsigned char *total_buffer;
|
unsigned char *total_buffer;
|
||||||
unsigned char *capture_buffer;
|
unsigned char *capture_buffer;
|
||||||
unsigned char *image_buffer;
|
unsigned char *row_buffer;
|
||||||
unsigned char *lastline;
|
unsigned char *lastline;
|
||||||
unsigned char *rescale_buffer;
|
GSList *rows;
|
||||||
int lines_captured, lines_recorded, empty_lines;
|
int lines_captured, lines_recorded, empty_lines;
|
||||||
int max_lines_captured, max_lines_recorded;
|
int max_lines_captured, max_lines_recorded;
|
||||||
int lines_total, lines_total_allocated;
|
int lines_total, lines_total_allocated;
|
||||||
gboolean loop_running;
|
gboolean loop_running;
|
||||||
gboolean deactivating;
|
gboolean deactivating;
|
||||||
struct usbexchange_data init_sequence;
|
struct usbexchange_data init_sequence;
|
||||||
|
struct libusb_transfer *flying_transfer;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
@@ -483,7 +343,7 @@ static int process_chunk(struct vfs5011_data *data, int transferred)
|
|||||||
unsigned char *linebuf = data->capture_buffer
|
unsigned char *linebuf = data->capture_buffer
|
||||||
+ i * VFS5011_LINE_SIZE;
|
+ i * VFS5011_LINE_SIZE;
|
||||||
|
|
||||||
if (get_deviation(linebuf + 8, VFS5011_IMAGE_WIDTH)
|
if (fpi_std_sq_dev(linebuf + 8, VFS5011_IMAGE_WIDTH)
|
||||||
< DEVIATION_THRESHOLD) {
|
< DEVIATION_THRESHOLD) {
|
||||||
if (data->lines_captured == 0)
|
if (data->lines_captured == 0)
|
||||||
continue;
|
continue;
|
||||||
@@ -505,13 +365,12 @@ static int process_chunk(struct vfs5011_data *data, int transferred)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((data->lastline == NULL)
|
if ((data->lastline == NULL)
|
||||||
|| (get_diff_norm(
|
|| (fpi_mean_sq_diff_norm(
|
||||||
data->lastline + 8,
|
data->lastline + 8,
|
||||||
linebuf + 8,
|
linebuf + 8,
|
||||||
VFS5011_IMAGE_WIDTH) >= DIFFERENCE_THRESHOLD)) {
|
VFS5011_IMAGE_WIDTH) >= DIFFERENCE_THRESHOLD)) {
|
||||||
data->lastline = data->image_buffer
|
data->lastline = g_malloc(VFS5011_LINE_SIZE);
|
||||||
+ data->lines_recorded
|
data->rows = g_slist_prepend(data->rows, data->lastline);
|
||||||
* VFS5011_LINE_SIZE;
|
|
||||||
memmove(data->lastline, linebuf, VFS5011_LINE_SIZE);
|
memmove(data->lastline, linebuf, VFS5011_LINE_SIZE);
|
||||||
data->lines_recorded++;
|
data->lines_recorded++;
|
||||||
if (data->lines_recorded >= data->max_lines_recorded) {
|
if (data->lines_recorded >= data->max_lines_recorded) {
|
||||||
@@ -524,34 +383,40 @@ static int process_chunk(struct vfs5011_data *data, int transferred)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void submit_image(struct fpi_ssm *ssm, struct vfs5011_data *data)
|
static void
|
||||||
|
submit_image(fpi_ssm *ssm,
|
||||||
|
struct vfs5011_data *data,
|
||||||
|
struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = (struct fp_img_dev *)ssm->priv;
|
struct fp_img *img;
|
||||||
int height = vfs5011_rescale_image(data->image_buffer,
|
|
||||||
data->lines_recorded,
|
|
||||||
data->rescale_buffer, MAXLINES);
|
|
||||||
struct fp_img *img = fpi_img_new(VFS5011_IMAGE_WIDTH * height);
|
|
||||||
|
|
||||||
if (img == NULL) {
|
if (data->lines_recorded == 0) {
|
||||||
fp_err("Failed to create image");
|
/* == FP_ENROLL_RETRY_TOO_SHORT */
|
||||||
fpi_ssm_mark_aborted(ssm, -1);
|
fpi_imgdev_session_error(dev, FP_VERIFY_RETRY_TOO_SHORT);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
img->flags = FP_IMG_V_FLIPPED;
|
g_assert (data->rows != NULL);
|
||||||
img->width = VFS5011_IMAGE_WIDTH;
|
|
||||||
img->height = height;
|
|
||||||
memmove(img->data, data->rescale_buffer, VFS5011_IMAGE_WIDTH * height);
|
|
||||||
|
|
||||||
fp_dbg("Image captured, commiting");
|
data->rows = g_slist_reverse(data->rows);
|
||||||
|
|
||||||
|
img = fpi_assemble_lines(&assembling_ctx, data->rows, data->lines_recorded);
|
||||||
|
|
||||||
|
g_slist_free_full(data->rows, g_free);
|
||||||
|
data->rows = NULL;
|
||||||
|
|
||||||
|
fp_dbg("Image captured, committing");
|
||||||
|
|
||||||
fpi_imgdev_image_captured(dev, img);
|
fpi_imgdev_image_captured(dev, img);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void chunk_capture_callback(struct libusb_transfer *transfer)
|
static void chunk_capture_callback(struct libusb_transfer *transfer)
|
||||||
{
|
{
|
||||||
struct fpi_ssm *ssm = (struct fpi_ssm *)transfer->user_data;
|
fpi_ssm *ssm = (fpi_ssm *)transfer->user_data;
|
||||||
struct fp_img_dev *dev = (struct fp_img_dev *)ssm->priv;
|
struct fp_img_dev *dev = fpi_ssm_get_user_data(ssm);
|
||||||
struct vfs5011_data *data = (struct vfs5011_data *)dev->priv;
|
struct vfs5011_data *data;
|
||||||
|
|
||||||
|
data = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
|
||||||
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) ||
|
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) ||
|
||||||
(transfer->status == LIBUSB_TRANSFER_TIMED_OUT)) {
|
(transfer->status == LIBUSB_TRANSFER_TIMED_OUT)) {
|
||||||
@@ -564,15 +429,20 @@ static void chunk_capture_callback(struct libusb_transfer *transfer)
|
|||||||
else
|
else
|
||||||
fpi_ssm_jump_to_state(ssm, DEV_ACTIVATE_READ_DATA);
|
fpi_ssm_jump_to_state(ssm, DEV_ACTIVATE_READ_DATA);
|
||||||
} else {
|
} else {
|
||||||
fp_err("Failed to capture data");
|
if (!data->deactivating) {
|
||||||
fpi_ssm_mark_aborted(ssm, -1);
|
fp_err("Failed to capture data");
|
||||||
|
fpi_ssm_mark_failed(ssm, -1);
|
||||||
|
} else {
|
||||||
|
fpi_ssm_mark_completed(ssm);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
libusb_free_transfer(transfer);
|
libusb_free_transfer(transfer);
|
||||||
|
data->flying_transfer = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int capture_chunk_async(struct vfs5011_data *data,
|
static int capture_chunk_async(struct vfs5011_data *data,
|
||||||
libusb_device_handle *handle, int nline,
|
libusb_device_handle *handle, int nline,
|
||||||
int timeout, struct fpi_ssm *ssm)
|
int timeout, fpi_ssm *ssm)
|
||||||
{
|
{
|
||||||
fp_dbg("capture_chunk_async: capture %d lines, already have %d",
|
fp_dbg("capture_chunk_async: capture %d lines, already have %d",
|
||||||
nline, data->lines_recorded);
|
nline, data->lines_recorded);
|
||||||
@@ -582,19 +452,12 @@ static int capture_chunk_async(struct vfs5011_data *data,
|
|||||||
STOP_CHECK_LINES = 50
|
STOP_CHECK_LINES = 50
|
||||||
};
|
};
|
||||||
|
|
||||||
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
data->flying_transfer = fpi_usb_alloc();
|
||||||
libusb_fill_bulk_transfer(transfer, handle, VFS5011_IN_ENDPOINT_DATA,
|
libusb_fill_bulk_transfer(data->flying_transfer, handle, VFS5011_IN_ENDPOINT_DATA,
|
||||||
data->capture_buffer,
|
data->capture_buffer,
|
||||||
nline * VFS5011_LINE_SIZE,
|
nline * VFS5011_LINE_SIZE,
|
||||||
chunk_capture_callback, ssm, timeout);
|
chunk_capture_callback, ssm, timeout);
|
||||||
return libusb_submit_transfer(transfer);
|
return libusb_submit_transfer(data->flying_transfer);
|
||||||
}
|
|
||||||
|
|
||||||
static void async_sleep_cb(void *data)
|
|
||||||
{
|
|
||||||
struct fpi_ssm *ssm = data;
|
|
||||||
|
|
||||||
fpi_ssm_next_state(ssm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -785,21 +648,29 @@ struct usb_action vfs5011_initiate_capture[] = {
|
|||||||
|
|
||||||
/* ====================== lifprint interface ======================= */
|
/* ====================== lifprint interface ======================= */
|
||||||
|
|
||||||
static void activate_loop(struct fpi_ssm *ssm)
|
static void activate_loop(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
enum {READ_TIMEOUT = 0};
|
enum {READ_TIMEOUT = 0};
|
||||||
|
|
||||||
struct fp_img_dev *dev = (struct fp_img_dev *)ssm->priv;
|
struct fp_img_dev *dev = user_data;
|
||||||
struct vfs5011_data *data = (struct vfs5011_data *)dev->priv;
|
struct vfs5011_data *data;
|
||||||
int r;
|
int r;
|
||||||
struct fpi_timeout *timeout;
|
fpi_timeout *timeout;
|
||||||
|
|
||||||
fp_dbg("main_loop: state %d", ssm->cur_state);
|
data = FP_INSTANCE_DATA(_dev);
|
||||||
|
|
||||||
switch (ssm->cur_state) {
|
fp_dbg("main_loop: state %d", fpi_ssm_get_cur_state(ssm));
|
||||||
|
|
||||||
|
if (data->deactivating) {
|
||||||
|
fp_dbg("deactivating, marking completed");
|
||||||
|
fpi_ssm_mark_completed(ssm);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||||
case DEV_ACTIVATE_REQUEST_FPRINT:
|
case DEV_ACTIVATE_REQUEST_FPRINT:
|
||||||
data->init_sequence.stepcount =
|
data->init_sequence.stepcount =
|
||||||
array_n_elements(vfs5011_initiate_capture);
|
G_N_ELEMENTS(vfs5011_initiate_capture);
|
||||||
data->init_sequence.actions = vfs5011_initiate_capture;
|
data->init_sequence.actions = vfs5011_initiate_capture;
|
||||||
data->init_sequence.device = dev;
|
data->init_sequence.device = dev;
|
||||||
if (data->init_sequence.receive_buf == NULL)
|
if (data->init_sequence.receive_buf == NULL)
|
||||||
@@ -819,34 +690,29 @@ static void activate_loop(struct fpi_ssm *ssm)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case DEV_ACTIVATE_READ_DATA:
|
case DEV_ACTIVATE_READ_DATA:
|
||||||
if (data->deactivating) {
|
r = capture_chunk_async(data, fpi_dev_get_usb_dev(FP_DEV(dev)), CAPTURE_LINES,
|
||||||
fp_dbg("deactivating, marking completed");
|
READ_TIMEOUT, ssm);
|
||||||
fpi_ssm_mark_completed(ssm);
|
if (r != 0) {
|
||||||
} else {
|
fp_err("Failed to capture data");
|
||||||
r = capture_chunk_async(data, dev->udev, CAPTURE_LINES,
|
fpi_imgdev_session_error(dev, r);
|
||||||
READ_TIMEOUT, ssm);
|
fpi_ssm_mark_failed(ssm, r);
|
||||||
if (r != 0) {
|
|
||||||
fp_err("Failed to capture data");
|
|
||||||
fpi_imgdev_session_error(dev, r);
|
|
||||||
fpi_ssm_mark_aborted(ssm, r);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DEV_ACTIVATE_DATA_COMPLETE:
|
case DEV_ACTIVATE_DATA_COMPLETE:
|
||||||
timeout = fpi_timeout_add(1, async_sleep_cb, ssm);
|
timeout = fpi_timeout_add(1, fpi_ssm_next_state_timeout_cb, _dev, ssm);
|
||||||
|
|
||||||
if (timeout == NULL) {
|
if (timeout == NULL) {
|
||||||
/* Failed to add timeout */
|
/* Failed to add timeout */
|
||||||
fp_err("failed to add timeout");
|
fp_err("failed to add timeout");
|
||||||
fpi_imgdev_session_error(dev, -1);
|
fpi_imgdev_session_error(dev, -1);
|
||||||
fpi_ssm_mark_aborted(ssm, -1);
|
fpi_ssm_mark_failed(ssm, -1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DEV_ACTIVATE_PREPARE_NEXT_CAPTURE:
|
case DEV_ACTIVATE_PREPARE_NEXT_CAPTURE:
|
||||||
data->init_sequence.stepcount =
|
data->init_sequence.stepcount =
|
||||||
array_n_elements(vfs5011_initiate_capture);
|
G_N_ELEMENTS(vfs5011_initiate_capture);
|
||||||
data->init_sequence.actions = vfs5011_initiate_capture;
|
data->init_sequence.actions = vfs5011_initiate_capture;
|
||||||
data->init_sequence.device = dev;
|
data->init_sequence.device = dev;
|
||||||
if (data->init_sequence.receive_buf == NULL)
|
if (data->init_sequence.receive_buf == NULL)
|
||||||
@@ -859,38 +725,47 @@ static void activate_loop(struct fpi_ssm *ssm)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void activate_loop_complete(struct fpi_ssm *ssm)
|
static void activate_loop_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = (struct fp_img_dev *)ssm->priv;
|
struct fp_img_dev *dev = user_data;
|
||||||
struct vfs5011_data *data = (struct vfs5011_data *)dev->priv;
|
struct vfs5011_data *data;
|
||||||
int r = ssm->error;
|
int r = fpi_ssm_get_error(ssm);
|
||||||
|
|
||||||
|
data = FP_INSTANCE_DATA(_dev);
|
||||||
|
|
||||||
fp_dbg("finishing");
|
fp_dbg("finishing");
|
||||||
if (data->init_sequence.receive_buf != NULL)
|
if (data->init_sequence.receive_buf != NULL)
|
||||||
g_free(data->init_sequence.receive_buf);
|
g_free(data->init_sequence.receive_buf);
|
||||||
data->init_sequence.receive_buf = NULL;
|
data->init_sequence.receive_buf = NULL;
|
||||||
data->loop_running = FALSE;
|
if (!data->deactivating && !r) {
|
||||||
submit_image(ssm, data);
|
submit_image(ssm, data, dev);
|
||||||
fpi_imgdev_report_finger_status(dev, FALSE);
|
fpi_imgdev_report_finger_status(dev, FALSE);
|
||||||
|
}
|
||||||
fpi_ssm_free(ssm);
|
fpi_ssm_free(ssm);
|
||||||
|
|
||||||
if (r)
|
data->loop_running = FALSE;
|
||||||
fpi_imgdev_session_error(dev, r);
|
|
||||||
|
|
||||||
if (data->deactivating)
|
if (data->deactivating) {
|
||||||
fpi_imgdev_deactivate_complete(dev);
|
fpi_imgdev_deactivate_complete(dev);
|
||||||
|
} else if (r) {
|
||||||
|
fpi_imgdev_session_error(dev, r);
|
||||||
|
} else {
|
||||||
|
start_scan(dev);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void open_loop(struct fpi_ssm *ssm)
|
|
||||||
{
|
|
||||||
struct fp_img_dev *dev = (struct fp_img_dev *)ssm->priv;
|
|
||||||
struct vfs5011_data *data = (struct vfs5011_data *)dev->priv;
|
|
||||||
|
|
||||||
switch (ssm->cur_state) {
|
static void open_loop(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
|
{
|
||||||
|
struct fp_img_dev *dev = user_data;
|
||||||
|
struct vfs5011_data *data;
|
||||||
|
|
||||||
|
data = FP_INSTANCE_DATA(_dev);
|
||||||
|
|
||||||
|
switch (fpi_ssm_get_cur_state(ssm)) {
|
||||||
case DEV_OPEN_START:
|
case DEV_OPEN_START:
|
||||||
data->init_sequence.stepcount =
|
data->init_sequence.stepcount =
|
||||||
array_n_elements(vfs5011_initialization);
|
G_N_ELEMENTS(vfs5011_initialization);
|
||||||
data->init_sequence.actions = vfs5011_initialization;
|
data->init_sequence.actions = vfs5011_initialization;
|
||||||
data->init_sequence.device = dev;
|
data->init_sequence.device = dev;
|
||||||
data->init_sequence.receive_buf =
|
data->init_sequence.receive_buf =
|
||||||
@@ -901,11 +776,12 @@ static void open_loop(struct fpi_ssm *ssm)
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static void open_loop_complete(struct fpi_ssm *ssm)
|
static void open_loop_complete(fpi_ssm *ssm, struct fp_dev *_dev, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *dev = (struct fp_img_dev *)ssm->priv;
|
struct fp_img_dev *dev = user_data;
|
||||||
struct vfs5011_data *data = (struct vfs5011_data *)dev->priv;
|
struct vfs5011_data *data;
|
||||||
|
|
||||||
|
data = FP_INSTANCE_DATA(_dev);
|
||||||
g_free(data->init_sequence.receive_buf);
|
g_free(data->init_sequence.receive_buf);
|
||||||
data->init_sequence.receive_buf = NULL;
|
data->init_sequence.receive_buf = NULL;
|
||||||
|
|
||||||
@@ -922,29 +798,22 @@ static int dev_open(struct fp_img_dev *dev, unsigned long driver_data)
|
|||||||
data = (struct vfs5011_data *)g_malloc0(sizeof(*data));
|
data = (struct vfs5011_data *)g_malloc0(sizeof(*data));
|
||||||
data->capture_buffer =
|
data->capture_buffer =
|
||||||
(unsigned char *)g_malloc0(CAPTURE_LINES * VFS5011_LINE_SIZE);
|
(unsigned char *)g_malloc0(CAPTURE_LINES * VFS5011_LINE_SIZE);
|
||||||
data->image_buffer =
|
fp_dev_set_instance_data(FP_DEV(dev), data);
|
||||||
(unsigned char *)g_malloc0(MAXLINES * VFS5011_LINE_SIZE);
|
|
||||||
data->rescale_buffer =
|
|
||||||
(unsigned char *)g_malloc0(MAXLINES * VFS5011_IMAGE_WIDTH);
|
|
||||||
dev->priv = data;
|
|
||||||
|
|
||||||
dev->dev->nr_enroll_stages = 1;
|
r = libusb_reset_device(fpi_dev_get_usb_dev(FP_DEV(dev)));
|
||||||
|
|
||||||
r = libusb_reset_device(dev->udev);
|
|
||||||
if (r != 0) {
|
if (r != 0) {
|
||||||
fp_err("Failed to reset the device");
|
fp_err("Failed to reset the device");
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = libusb_claim_interface(dev->udev, 0);
|
r = libusb_claim_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||||
if (r != 0) {
|
if (r != 0) {
|
||||||
fp_err("Failed to claim interface");
|
fp_err("Failed to claim interface: %s", libusb_error_name(r));
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct fpi_ssm *ssm;
|
fpi_ssm *ssm;
|
||||||
ssm = fpi_ssm_new(dev->dev, open_loop, DEV_OPEN_NUM_STATES);
|
ssm = fpi_ssm_new(FP_DEV(dev), open_loop, DEV_OPEN_NUM_STATES, dev);
|
||||||
ssm->priv = dev;
|
|
||||||
fpi_ssm_start(ssm, open_loop_complete);
|
fpi_ssm_start(ssm, open_loop_complete);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -952,47 +821,65 @@ static int dev_open(struct fp_img_dev *dev, unsigned long driver_data)
|
|||||||
|
|
||||||
static void dev_close(struct fp_img_dev *dev)
|
static void dev_close(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
libusb_release_interface(dev->udev, 0);
|
libusb_release_interface(fpi_dev_get_usb_dev(FP_DEV(dev)), 0);
|
||||||
struct vfs5011_data *data = (struct vfs5011_data *)dev->priv;
|
struct vfs5011_data *data;
|
||||||
|
data = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
if (data != NULL) {
|
if (data != NULL) {
|
||||||
g_free(data->capture_buffer);
|
g_free(data->capture_buffer);
|
||||||
g_free(data->image_buffer);
|
g_slist_free_full(data->rows, g_free);
|
||||||
g_free(data->rescale_buffer);
|
|
||||||
g_free(data);
|
g_free(data);
|
||||||
}
|
}
|
||||||
fpi_imgdev_close_complete(dev);
|
fpi_imgdev_close_complete(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dev_activate(struct fp_img_dev *dev, enum fp_imgdev_state state)
|
static void start_scan(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct vfs5011_data *data = (struct vfs5011_data *)dev->priv;
|
struct vfs5011_data *data;
|
||||||
struct fpi_ssm *ssm;
|
fpi_ssm *ssm;
|
||||||
|
|
||||||
fp_dbg("device initialized");
|
data = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
data->deactivating = FALSE;
|
|
||||||
data->loop_running = TRUE;
|
data->loop_running = TRUE;
|
||||||
|
|
||||||
fp_dbg("creating ssm");
|
fp_dbg("creating ssm");
|
||||||
ssm = fpi_ssm_new(dev->dev, activate_loop, DEV_ACTIVATE_NUM_STATES);
|
ssm = fpi_ssm_new(FP_DEV(dev), activate_loop, DEV_ACTIVATE_NUM_STATES, dev);
|
||||||
ssm->priv = dev;
|
|
||||||
fp_dbg("starting ssm");
|
fp_dbg("starting ssm");
|
||||||
fpi_ssm_start(ssm, activate_loop_complete);
|
fpi_ssm_start(ssm, activate_loop_complete);
|
||||||
fp_dbg("ssm done, getting out");
|
fp_dbg("ssm done, getting out");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dev_activate(struct fp_img_dev *dev)
|
||||||
|
{
|
||||||
|
struct vfs5011_data *data;
|
||||||
|
|
||||||
|
data = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
fp_dbg("device initialized");
|
||||||
|
data->deactivating = FALSE;
|
||||||
|
|
||||||
|
start_scan(dev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dev_deactivate(struct fp_img_dev *dev)
|
static void dev_deactivate(struct fp_img_dev *dev)
|
||||||
{
|
{
|
||||||
struct vfs5011_data *data = dev->priv;
|
int r;
|
||||||
if (data->loop_running)
|
struct vfs5011_data *data;
|
||||||
|
|
||||||
|
data = FP_INSTANCE_DATA(FP_DEV(dev));
|
||||||
|
if (data->loop_running) {
|
||||||
data->deactivating = TRUE;
|
data->deactivating = TRUE;
|
||||||
else
|
if (data->flying_transfer) {
|
||||||
|
r = libusb_cancel_transfer(data->flying_transfer);
|
||||||
|
if (r < 0)
|
||||||
|
fp_dbg("cancel failed error %d", r);
|
||||||
|
}
|
||||||
|
} else
|
||||||
fpi_imgdev_deactivate_complete(dev);
|
fpi_imgdev_deactivate_complete(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct usb_id id_table[] = {
|
static const struct usb_id id_table[] = {
|
||||||
|
{ .vendor = 0x138a, .product = 0x0010 /* Validity device from some Toshiba laptops */ },
|
||||||
{ .vendor = 0x138a, .product = 0x0011 /* vfs5011 */ },
|
{ .vendor = 0x138a, .product = 0x0011 /* vfs5011 */ },
|
||||||
|
{ .vendor = 0x138a, .product = 0x0015 /* Validity device from Lenovo Preferred Pro USB Fingerprint Keyboard KUF1256 */ },
|
||||||
{ .vendor = 0x138a, .product = 0x0017 /* Validity device from Lenovo T440 laptops */ },
|
{ .vendor = 0x138a, .product = 0x0017 /* Validity device from Lenovo T440 laptops */ },
|
||||||
{ .vendor = 0x138a, .product = 0x0018 /* one more Validity device */ },
|
{ .vendor = 0x138a, .product = 0x0018 /* one more Validity device */ },
|
||||||
{ 0, 0, 0, },
|
{ 0, 0, 0, },
|
||||||
|
|||||||
39
libfprint/drivers_api.h
Normal file
39
libfprint/drivers_api.h
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Driver API definitions
|
||||||
|
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __DRIVERS_API_H__
|
||||||
|
#define __DRIVERS_API_H__
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include "fprint.h"
|
||||||
|
#include "fpi-log.h"
|
||||||
|
#include "fpi-dev.h"
|
||||||
|
#include "fpi-dev-img.h"
|
||||||
|
#include "fpi-core.h"
|
||||||
|
#include "fpi-ssm.h"
|
||||||
|
#include "fpi-poll.h"
|
||||||
|
#include "fpi-dev.h"
|
||||||
|
#include "fpi-usb.h"
|
||||||
|
#include "fpi-img.h"
|
||||||
|
#include "fpi-assembling.h"
|
||||||
|
#include "drivers/driver_ids.h"
|
||||||
|
|
||||||
|
#endif
|
||||||
171
libfprint/drv.c
171
libfprint/drv.c
@@ -1,171 +0,0 @@
|
|||||||
/*
|
|
||||||
* Functions to assist with asynchronous driver <---> library communications
|
|
||||||
* 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 "drv"
|
|
||||||
|
|
||||||
#include <config.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#include "fp_internal.h"
|
|
||||||
|
|
||||||
/* SSM: sequential state machine
|
|
||||||
* Asynchronous driver design encourages some kind of state machine behind it.
|
|
||||||
* In most cases, the state machine is entirely linear - you only go to the
|
|
||||||
* next state, you never jump or go backwards. The SSM functions help you
|
|
||||||
* implement such a machine.
|
|
||||||
*
|
|
||||||
* e.g. S1 --> S2 --> S3 --> S4
|
|
||||||
* S1 is the start state
|
|
||||||
* There is also an implicit error state and an implicit accepting state
|
|
||||||
* (both with implicit edges from every state).
|
|
||||||
*
|
|
||||||
* You can also jump to any arbitrary state (while marking completion of the
|
|
||||||
* current state) while the machine is running. In other words there are
|
|
||||||
* implicit edges linking one state to every other state. OK, we're stretching
|
|
||||||
* the "state machine" description at this point.
|
|
||||||
*
|
|
||||||
* To create a ssm, you pass a state handler function and the total number of
|
|
||||||
* states (4 in the above example).
|
|
||||||
*
|
|
||||||
* To start a ssm, you pass in a completion callback function which gets
|
|
||||||
* called when the ssm completes (both on error and on failure).
|
|
||||||
*
|
|
||||||
* To iterate to the next state, call fpi_ssm_next_state(). It is legal to
|
|
||||||
* attempt to iterate beyond the final state - this is equivalent to marking
|
|
||||||
* the ssm as successfully completed.
|
|
||||||
*
|
|
||||||
* To mark successful completion of a SSM, either iterate beyond the final
|
|
||||||
* state or call fpi_ssm_mark_completed() from any state.
|
|
||||||
*
|
|
||||||
* To mark failed completion of a SSM, call fpi_ssm_mark_aborted() from any
|
|
||||||
* state. You must pass a non-zero error code.
|
|
||||||
*
|
|
||||||
* Your state handling function looks at ssm->cur_state in order to determine
|
|
||||||
* the current state and hence which operations to perform (a switch statement
|
|
||||||
* is appropriate).
|
|
||||||
* Typically, the state handling function fires off an asynchronous libusb
|
|
||||||
* transfer, and the callback function iterates the machine to the next state
|
|
||||||
* upon success (or aborts the machine on transfer failure).
|
|
||||||
*
|
|
||||||
* Your completion callback should examine ssm->error in order to determine
|
|
||||||
* whether the ssm completed or failed. An error code of zero indicates
|
|
||||||
* successful completion.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Allocate a new ssm */
|
|
||||||
struct fpi_ssm *fpi_ssm_new(struct fp_dev *dev, ssm_handler_fn handler,
|
|
||||||
int nr_states)
|
|
||||||
{
|
|
||||||
struct fpi_ssm *machine;
|
|
||||||
BUG_ON(nr_states < 1);
|
|
||||||
|
|
||||||
machine = g_malloc0(sizeof(*machine));
|
|
||||||
machine->handler = handler;
|
|
||||||
machine->nr_states = nr_states;
|
|
||||||
machine->dev = dev;
|
|
||||||
machine->completed = TRUE;
|
|
||||||
return machine;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Free a ssm */
|
|
||||||
void fpi_ssm_free(struct fpi_ssm *machine)
|
|
||||||
{
|
|
||||||
if (!machine)
|
|
||||||
return;
|
|
||||||
g_free(machine);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Invoke the state handler */
|
|
||||||
static void __ssm_call_handler(struct fpi_ssm *machine)
|
|
||||||
{
|
|
||||||
fp_dbg("%p entering state %d", machine, machine->cur_state);
|
|
||||||
machine->handler(machine);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Start a ssm. You can also restart a completed or aborted ssm. */
|
|
||||||
void fpi_ssm_start(struct fpi_ssm *ssm, ssm_completed_fn callback)
|
|
||||||
{
|
|
||||||
BUG_ON(!ssm->completed);
|
|
||||||
ssm->callback = callback;
|
|
||||||
ssm->cur_state = 0;
|
|
||||||
ssm->completed = FALSE;
|
|
||||||
ssm->error = 0;
|
|
||||||
__ssm_call_handler(ssm);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __subsm_complete(struct fpi_ssm *ssm)
|
|
||||||
{
|
|
||||||
struct fpi_ssm *parent = ssm->parentsm;
|
|
||||||
BUG_ON(!parent);
|
|
||||||
if (ssm->error)
|
|
||||||
fpi_ssm_mark_aborted(parent, ssm->error);
|
|
||||||
else
|
|
||||||
fpi_ssm_next_state(parent);
|
|
||||||
fpi_ssm_free(ssm);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* start a SSM as a child of another. if the child completes successfully, the
|
|
||||||
* parent will be advanced to the next state. if the child aborts, the parent
|
|
||||||
* will be aborted with the same error code. the child will be automatically
|
|
||||||
* freed upon completion/abortion. */
|
|
||||||
void fpi_ssm_start_subsm(struct fpi_ssm *parent, struct fpi_ssm *child)
|
|
||||||
{
|
|
||||||
child->parentsm = parent;
|
|
||||||
fpi_ssm_start(child, __subsm_complete);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Mark a ssm as completed successfully. */
|
|
||||||
void fpi_ssm_mark_completed(struct fpi_ssm *machine)
|
|
||||||
{
|
|
||||||
BUG_ON(machine->completed);
|
|
||||||
machine->completed = TRUE;
|
|
||||||
fp_dbg("%p completed with status %d", machine, machine->error);
|
|
||||||
if (machine->callback)
|
|
||||||
machine->callback(machine);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Mark a ssm as aborted with error. */
|
|
||||||
void fpi_ssm_mark_aborted(struct fpi_ssm *machine, int error)
|
|
||||||
{
|
|
||||||
fp_dbg("error %d from state %d", error, machine->cur_state);
|
|
||||||
BUG_ON(error == 0);
|
|
||||||
machine->error = error;
|
|
||||||
fpi_ssm_mark_completed(machine);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Iterate to next state of a ssm */
|
|
||||||
void fpi_ssm_next_state(struct fpi_ssm *machine)
|
|
||||||
{
|
|
||||||
BUG_ON(machine->completed);
|
|
||||||
machine->cur_state++;
|
|
||||||
if (machine->cur_state == machine->nr_states) {
|
|
||||||
fpi_ssm_mark_completed(machine);
|
|
||||||
} else {
|
|
||||||
__ssm_call_handler(machine);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void fpi_ssm_jump_to_state(struct fpi_ssm *machine, int state)
|
|
||||||
{
|
|
||||||
BUG_ON(machine->completed);
|
|
||||||
BUG_ON(state >= machine->nr_states);
|
|
||||||
machine->cur_state = state;
|
|
||||||
__ssm_call_handler(machine);
|
|
||||||
}
|
|
||||||
|
|
||||||
1
libfprint/empty_file
Normal file
1
libfprint/empty_file
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -21,58 +21,40 @@
|
|||||||
#define __FPRINT_INTERNAL_H__
|
#define __FPRINT_INTERNAL_H__
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include <libusb.h>
|
#include <libusb.h>
|
||||||
|
|
||||||
#include <fprint.h>
|
#include "nbis-helpers.h"
|
||||||
|
#include "fprint.h"
|
||||||
|
#include "fpi-dev.h"
|
||||||
|
#include "fpi-core.h"
|
||||||
|
#include "fpi-log.h"
|
||||||
|
#include "fpi-dev-img.h"
|
||||||
|
#include "fpi-data.h"
|
||||||
|
#include "fpi-img.h"
|
||||||
|
#include "drivers/driver_ids.h"
|
||||||
|
|
||||||
#define array_n_elements(array) (sizeof(array) / sizeof(array[0]))
|
/* Global variables */
|
||||||
|
extern libusb_context *fpi_usb_ctx;
|
||||||
|
extern GSList *opened_devices;
|
||||||
|
|
||||||
#define container_of(ptr, type, member) ({ \
|
/* fp_print_data structure definition */
|
||||||
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
|
enum fp_print_data_type {
|
||||||
(type *)( (char *)__mptr - offsetof(type,member) );})
|
PRINT_DATA_RAW = 0, /* memset-imposed default */
|
||||||
|
PRINT_DATA_NBIS_MINUTIAE
|
||||||
enum fpi_log_level {
|
|
||||||
FPRINT_LOG_LEVEL_DEBUG,
|
|
||||||
FPRINT_LOG_LEVEL_INFO,
|
|
||||||
FPRINT_LOG_LEVEL_WARNING,
|
|
||||||
FPRINT_LOG_LEVEL_ERROR,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void fpi_log(enum fpi_log_level, const char *component, const char *function,
|
struct fp_print_data {
|
||||||
const char *format, ...);
|
uint16_t driver_id;
|
||||||
|
uint32_t devtype;
|
||||||
#ifndef FP_COMPONENT
|
enum fp_print_data_type type;
|
||||||
#define FP_COMPONENT NULL
|
GSList *prints;
|
||||||
#endif
|
};
|
||||||
|
|
||||||
#ifdef ENABLE_LOGGING
|
|
||||||
#define _fpi_log(level, fmt...) fpi_log(level, FP_COMPONENT, __FUNCTION__, fmt)
|
|
||||||
#else
|
|
||||||
#define _fpi_log(level, fmt...)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef ENABLE_DEBUG_LOGGING
|
|
||||||
#define fp_dbg(fmt...) _fpi_log(FPRINT_LOG_LEVEL_DEBUG, fmt)
|
|
||||||
#else
|
|
||||||
#define fp_dbg(fmt...)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define fp_info(fmt...) _fpi_log(FPRINT_LOG_LEVEL_INFO, fmt)
|
|
||||||
#define fp_warn(fmt...) _fpi_log(FPRINT_LOG_LEVEL_WARNING, fmt)
|
|
||||||
#define fp_err(fmt...) _fpi_log(FPRINT_LOG_LEVEL_ERROR, fmt)
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
#define BUG_ON(condition) \
|
|
||||||
if ((condition)) fp_err("BUG at %s:%d", __FILE__, __LINE__)
|
|
||||||
#else
|
|
||||||
#define BUG_ON(condition)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define BUG() BUG_ON(1)
|
|
||||||
|
|
||||||
|
/* fp_dev structure definition */
|
||||||
enum fp_dev_state {
|
enum fp_dev_state {
|
||||||
DEV_STATE_INITIAL = 0,
|
DEV_STATE_INITIAL = 0,
|
||||||
DEV_STATE_ERROR,
|
DEV_STATE_ERROR,
|
||||||
@@ -97,16 +79,20 @@ enum fp_dev_state {
|
|||||||
DEV_STATE_CAPTURE_STOPPING,
|
DEV_STATE_CAPTURE_STOPPING,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fp_driver **fprint_get_drivers (void);
|
|
||||||
|
|
||||||
struct fp_dev {
|
struct fp_dev {
|
||||||
struct fp_driver *drv;
|
struct fp_driver *drv;
|
||||||
libusb_device_handle *udev;
|
|
||||||
uint32_t devtype;
|
uint32_t devtype;
|
||||||
void *priv;
|
|
||||||
|
/* only valid if drv->type == DRIVER_IMAGING */
|
||||||
|
struct fp_img_dev *img_dev;
|
||||||
|
/* Link to the instance specific struct */
|
||||||
|
void *instance_data;
|
||||||
|
|
||||||
int nr_enroll_stages;
|
int nr_enroll_stages;
|
||||||
|
|
||||||
|
/* FIXME: This will eventually have a bus type */
|
||||||
|
libusb_device_handle *udev;
|
||||||
|
|
||||||
/* read-only to drivers */
|
/* read-only to drivers */
|
||||||
struct fp_print_data *verify_data;
|
struct fp_print_data *verify_data;
|
||||||
|
|
||||||
@@ -119,62 +105,33 @@ struct fp_dev {
|
|||||||
/* FIXME: convert this to generic state operational data mechanism? */
|
/* FIXME: convert this to generic state operational data mechanism? */
|
||||||
fp_dev_open_cb open_cb;
|
fp_dev_open_cb open_cb;
|
||||||
void *open_cb_data;
|
void *open_cb_data;
|
||||||
fp_dev_close_cb close_cb;
|
fp_operation_stop_cb close_cb;
|
||||||
void *close_cb_data;
|
void *close_cb_data;
|
||||||
fp_enroll_stage_cb enroll_stage_cb;
|
fp_enroll_stage_cb enroll_stage_cb;
|
||||||
void *enroll_stage_cb_data;
|
void *enroll_stage_cb_data;
|
||||||
fp_enroll_stop_cb enroll_stop_cb;
|
fp_operation_stop_cb enroll_stop_cb;
|
||||||
void *enroll_stop_cb_data;
|
void *enroll_stop_cb_data;
|
||||||
fp_verify_cb verify_cb;
|
fp_img_operation_cb verify_cb;
|
||||||
void *verify_cb_data;
|
void *verify_cb_data;
|
||||||
fp_verify_stop_cb verify_stop_cb;
|
fp_operation_stop_cb verify_stop_cb;
|
||||||
void *verify_stop_cb_data;
|
void *verify_stop_cb_data;
|
||||||
fp_identify_cb identify_cb;
|
fp_identify_cb identify_cb;
|
||||||
void *identify_cb_data;
|
void *identify_cb_data;
|
||||||
fp_identify_stop_cb identify_stop_cb;
|
fp_operation_stop_cb identify_stop_cb;
|
||||||
void *identify_stop_cb_data;
|
void *identify_stop_cb_data;
|
||||||
fp_capture_cb capture_cb;
|
fp_img_operation_cb capture_cb;
|
||||||
void *capture_cb_data;
|
void *capture_cb_data;
|
||||||
fp_capture_stop_cb capture_stop_cb;
|
fp_operation_stop_cb capture_stop_cb;
|
||||||
void *capture_stop_cb_data;
|
void *capture_stop_cb_data;
|
||||||
|
|
||||||
/* FIXME: better place to put this? */
|
/* FIXME: better place to put this? */
|
||||||
struct fp_print_data **identify_gallery;
|
struct fp_print_data **identify_gallery;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum fp_imgdev_state {
|
/* fp_img_dev structure definition */
|
||||||
IMGDEV_STATE_INACTIVE,
|
|
||||||
IMGDEV_STATE_AWAIT_FINGER_ON,
|
|
||||||
IMGDEV_STATE_CAPTURE,
|
|
||||||
IMGDEV_STATE_AWAIT_FINGER_OFF,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum fp_imgdev_action {
|
|
||||||
IMG_ACTION_NONE = 0,
|
|
||||||
IMG_ACTION_ENROLL,
|
|
||||||
IMG_ACTION_VERIFY,
|
|
||||||
IMG_ACTION_IDENTIFY,
|
|
||||||
IMG_ACTION_CAPTURE,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum fp_imgdev_enroll_state {
|
|
||||||
IMG_ACQUIRE_STATE_NONE = 0,
|
|
||||||
IMG_ACQUIRE_STATE_ACTIVATING,
|
|
||||||
IMG_ACQUIRE_STATE_AWAIT_FINGER_ON,
|
|
||||||
IMG_ACQUIRE_STATE_AWAIT_IMAGE,
|
|
||||||
IMG_ACQUIRE_STATE_AWAIT_FINGER_OFF,
|
|
||||||
IMG_ACQUIRE_STATE_DONE,
|
|
||||||
IMG_ACQUIRE_STATE_DEACTIVATING,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum fp_imgdev_verify_state {
|
|
||||||
IMG_VERIFY_STATE_NONE = 0,
|
|
||||||
IMG_VERIFY_STATE_ACTIVATING
|
|
||||||
};
|
|
||||||
|
|
||||||
struct fp_img_dev {
|
struct fp_img_dev {
|
||||||
struct fp_dev *dev;
|
struct fp_dev *parent;
|
||||||
libusb_device_handle *udev;
|
|
||||||
enum fp_imgdev_action action;
|
enum fp_imgdev_action action;
|
||||||
int action_state;
|
int action_state;
|
||||||
|
|
||||||
@@ -186,134 +143,18 @@ struct fp_img_dev {
|
|||||||
|
|
||||||
/* FIXME: better place to put this? */
|
/* FIXME: better place to put this? */
|
||||||
size_t identify_match_offset;
|
size_t identify_match_offset;
|
||||||
|
|
||||||
void *priv;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
int fpi_imgdev_get_img_width(struct fp_img_dev *imgdev);
|
/* fp_driver structure definition */
|
||||||
int fpi_imgdev_get_img_height(struct fp_img_dev *imgdev);
|
|
||||||
|
|
||||||
struct usb_id {
|
|
||||||
uint16_t vendor;
|
|
||||||
uint16_t product;
|
|
||||||
unsigned long driver_data;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum fp_driver_type {
|
|
||||||
DRIVER_PRIMITIVE = 0,
|
|
||||||
DRIVER_IMAGING = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct fp_driver {
|
|
||||||
const uint16_t id;
|
|
||||||
const char *name;
|
|
||||||
const char *full_name;
|
|
||||||
const struct usb_id * const id_table;
|
|
||||||
enum fp_driver_type type;
|
|
||||||
enum fp_scan_type scan_type;
|
|
||||||
|
|
||||||
void *priv;
|
|
||||||
|
|
||||||
/* Device operations */
|
|
||||||
int (*discover)(struct libusb_device_descriptor *dsc, uint32_t *devtype);
|
|
||||||
int (*open)(struct fp_dev *dev, unsigned long driver_data);
|
|
||||||
void (*close)(struct fp_dev *dev);
|
|
||||||
int (*enroll_start)(struct fp_dev *dev);
|
|
||||||
int (*enroll_stop)(struct fp_dev *dev);
|
|
||||||
int (*verify_start)(struct fp_dev *dev);
|
|
||||||
int (*verify_stop)(struct fp_dev *dev, gboolean iterating);
|
|
||||||
int (*identify_start)(struct fp_dev *dev);
|
|
||||||
int (*identify_stop)(struct fp_dev *dev, gboolean iterating);
|
|
||||||
int (*capture_start)(struct fp_dev *dev);
|
|
||||||
int (*capture_stop)(struct fp_dev *dev);
|
|
||||||
};
|
|
||||||
|
|
||||||
enum fp_print_data_type fpi_driver_get_data_type(struct fp_driver *drv);
|
|
||||||
|
|
||||||
/* flags for fp_img_driver.flags */
|
|
||||||
#define FP_IMGDRV_SUPPORTS_UNCONDITIONAL_CAPTURE (1 << 0)
|
|
||||||
|
|
||||||
struct fp_img_driver {
|
|
||||||
struct fp_driver driver;
|
|
||||||
uint16_t flags;
|
|
||||||
int img_width;
|
|
||||||
int img_height;
|
|
||||||
int bz3_threshold;
|
|
||||||
|
|
||||||
/* Device operations */
|
|
||||||
int (*open)(struct fp_img_dev *dev, unsigned long driver_data);
|
|
||||||
void (*close)(struct fp_img_dev *dev);
|
|
||||||
int (*activate)(struct fp_img_dev *dev, enum fp_imgdev_state state);
|
|
||||||
int (*change_state)(struct fp_img_dev *dev, enum fp_imgdev_state state);
|
|
||||||
void (*deactivate)(struct fp_img_dev *dev);
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef ENABLE_UPEKTS
|
|
||||||
extern struct fp_driver upekts_driver;
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_UPEKE2
|
|
||||||
extern struct fp_driver upeke2_driver;
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_UPEKTC
|
|
||||||
extern struct fp_img_driver upektc_driver;
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_UPEKSONLY
|
|
||||||
extern struct fp_img_driver upeksonly_driver;
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_URU4000
|
|
||||||
extern struct fp_img_driver uru4000_driver;
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_AES1610
|
|
||||||
extern struct fp_img_driver aes1610_driver;
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_AES1660
|
|
||||||
extern struct fp_img_driver aes1660_driver;
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_AES2501
|
|
||||||
extern struct fp_img_driver aes2501_driver;
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_AES2550
|
|
||||||
extern struct fp_img_driver aes2550_driver;
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_AES2660
|
|
||||||
extern struct fp_img_driver aes2660_driver;
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_AES3500
|
|
||||||
extern struct fp_img_driver aes3500_driver;
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_AES4000
|
|
||||||
extern struct fp_img_driver aes4000_driver;
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_FDU2000
|
|
||||||
extern struct fp_img_driver fdu2000_driver;
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_VCOM5S
|
|
||||||
extern struct fp_img_driver vcom5s_driver;
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_VFS101
|
|
||||||
extern struct fp_img_driver vfs101_driver;
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_VFS301
|
|
||||||
extern struct fp_img_driver vfs301_driver;
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_VFS5011
|
|
||||||
extern struct fp_img_driver vfs5011_driver;
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_UPEKTC_IMG
|
|
||||||
extern struct fp_img_driver upektc_img_driver;
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_ETES603
|
|
||||||
extern struct fp_img_driver etes603_driver;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern libusb_context *fpi_usb_ctx;
|
|
||||||
extern GSList *opened_devices;
|
|
||||||
|
|
||||||
void fpi_img_driver_setup(struct fp_img_driver *idriver);
|
|
||||||
|
|
||||||
|
/* fp_img_driver structure definition */
|
||||||
|
#define container_of(ptr, type, member) ({ \
|
||||||
|
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
|
||||||
|
(type *)( (char *)__mptr - offsetof(type,member) );})
|
||||||
#define fpi_driver_to_img_driver(drv) \
|
#define fpi_driver_to_img_driver(drv) \
|
||||||
container_of((drv), struct fp_img_driver, driver)
|
container_of((drv), struct fp_img_driver, driver)
|
||||||
|
|
||||||
|
/* fp_dscv_dev structure definition */
|
||||||
struct fp_dscv_dev {
|
struct fp_dscv_dev {
|
||||||
struct libusb_device *udev;
|
struct libusb_device *udev;
|
||||||
struct fp_driver *drv;
|
struct fp_driver *drv;
|
||||||
@@ -321,6 +162,7 @@ struct fp_dscv_dev {
|
|||||||
uint32_t devtype;
|
uint32_t devtype;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* fp_dscv_print structure definition */
|
||||||
struct fp_dscv_print {
|
struct fp_dscv_print {
|
||||||
uint16_t driver_id;
|
uint16_t driver_id;
|
||||||
uint32_t devtype;
|
uint32_t devtype;
|
||||||
@@ -328,161 +170,72 @@ struct fp_dscv_print {
|
|||||||
char *path;
|
char *path;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum fp_print_data_type {
|
/* fp_minutia structure definition */
|
||||||
PRINT_DATA_RAW = 0, /* memset-imposed default */
|
struct fp_minutia {
|
||||||
PRINT_DATA_NBIS_MINUTIAE,
|
int x;
|
||||||
|
int y;
|
||||||
|
int ex;
|
||||||
|
int ey;
|
||||||
|
int direction;
|
||||||
|
double reliability;
|
||||||
|
int type;
|
||||||
|
int appearing;
|
||||||
|
int feature_id;
|
||||||
|
int *nbrs;
|
||||||
|
int *ridge_counts;
|
||||||
|
int num_nbrs;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fp_print_data_item {
|
/* fp_minutiae structure definition */
|
||||||
size_t length;
|
|
||||||
unsigned char data[0];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct fp_print_data {
|
|
||||||
uint16_t driver_id;
|
|
||||||
uint32_t devtype;
|
|
||||||
enum fp_print_data_type type;
|
|
||||||
GSList *prints;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct fpi_print_data_fp2 {
|
|
||||||
char prefix[3];
|
|
||||||
uint16_t driver_id;
|
|
||||||
uint32_t devtype;
|
|
||||||
unsigned char data_type;
|
|
||||||
unsigned char data[0];
|
|
||||||
} __attribute__((__packed__));
|
|
||||||
|
|
||||||
struct fpi_print_data_item_fp2 {
|
|
||||||
uint32_t length;
|
|
||||||
unsigned char data[0];
|
|
||||||
} __attribute__((__packed__));
|
|
||||||
|
|
||||||
void fpi_data_exit(void);
|
|
||||||
struct fp_print_data *fpi_print_data_new(struct fp_dev *dev);
|
|
||||||
struct fp_print_data_item *fpi_print_data_item_new(size_t length);
|
|
||||||
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);
|
|
||||||
|
|
||||||
struct fp_minutiae {
|
struct fp_minutiae {
|
||||||
int alloc;
|
int alloc;
|
||||||
int num;
|
int num;
|
||||||
struct fp_minutia **list;
|
struct fp_minutia **list;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* bit values for fp_img.flags */
|
/* Defined in fpi-dev-img.c */
|
||||||
#define FP_IMG_V_FLIPPED (1<<0)
|
void fpi_img_driver_setup(struct fp_img_driver *idriver);
|
||||||
#define FP_IMG_H_FLIPPED (1<<1)
|
int fpi_imgdev_get_img_width(struct fp_img_dev *imgdev);
|
||||||
#define FP_IMG_COLORS_INVERTED (1<<2)
|
int fpi_imgdev_get_img_height(struct fp_img_dev *imgdev);
|
||||||
#define FP_IMG_BINARIZED_FORM (1<<3)
|
|
||||||
|
|
||||||
#define FP_IMG_STANDARDIZATION_FLAGS (FP_IMG_V_FLIPPED | FP_IMG_H_FLIPPED \
|
/* Exported for use in command-line tools
|
||||||
| FP_IMG_COLORS_INVERTED)
|
* Defined in fpi-core.c */
|
||||||
|
struct fp_driver **fprint_get_drivers (void);
|
||||||
|
|
||||||
struct fp_img {
|
/* Defined in fpi-core.c */
|
||||||
int width;
|
enum fp_print_data_type fpi_driver_get_data_type(struct fp_driver *drv);
|
||||||
int height;
|
|
||||||
size_t length;
|
|
||||||
uint16_t flags;
|
|
||||||
struct fp_minutiae *minutiae;
|
|
||||||
unsigned char *binarized;
|
|
||||||
unsigned char data[0];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct fp_img *fpi_img_new(size_t length);
|
/* Defined in fpi-data.c */
|
||||||
struct fp_img *fpi_img_new_for_imgdev(struct fp_img_dev *dev);
|
void fpi_data_exit(void);
|
||||||
struct fp_img *fpi_img_resize(struct fp_img *img, size_t newsize);
|
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);
|
||||||
|
|
||||||
|
/* Defined in fpi-img.c */
|
||||||
gboolean fpi_img_is_sane(struct fp_img *img);
|
gboolean fpi_img_is_sane(struct fp_img *img);
|
||||||
int fpi_img_detect_minutiae(struct fp_img *img);
|
|
||||||
int fpi_img_to_print_data(struct fp_img_dev *imgdev, struct fp_img *img,
|
int fpi_img_to_print_data(struct fp_img_dev *imgdev, struct fp_img *img,
|
||||||
struct fp_print_data **ret);
|
struct fp_print_data **ret);
|
||||||
int fpi_img_compare_print_data(struct fp_print_data *enrolled_print,
|
int fpi_img_compare_print_data(struct fp_print_data *enrolled_print,
|
||||||
struct fp_print_data *new_print);
|
struct fp_print_data *new_print);
|
||||||
int fpi_img_compare_print_data_to_gallery(struct fp_print_data *print,
|
int fpi_img_compare_print_data_to_gallery(struct fp_print_data *print,
|
||||||
struct fp_print_data **gallery, int match_threshold, size_t *match_offset);
|
struct fp_print_data **gallery, int match_threshold, size_t *match_offset);
|
||||||
struct fp_img *fpi_im_resize(struct fp_img *img, unsigned int w_factor, unsigned int h_factor);
|
|
||||||
|
|
||||||
/* polling and timeouts */
|
|
||||||
|
|
||||||
|
/* Defined in fpi-poll.c */
|
||||||
|
void fpi_timeout_cancel_all_for_dev(struct fp_dev *dev);
|
||||||
void fpi_poll_init(void);
|
void fpi_poll_init(void);
|
||||||
void fpi_poll_exit(void);
|
void fpi_poll_exit(void);
|
||||||
|
|
||||||
typedef void (*fpi_timeout_fn)(void *data);
|
/* Defined in fpi-async.c */
|
||||||
|
void fpi_drvcb_capture_started(struct fp_dev *dev, int status);
|
||||||
struct fpi_timeout;
|
void fpi_drvcb_report_capture_result(struct fp_dev *dev, int result,
|
||||||
struct fpi_timeout *fpi_timeout_add(unsigned int msec, fpi_timeout_fn callback,
|
|
||||||
void *data);
|
|
||||||
void fpi_timeout_cancel(struct fpi_timeout *timeout);
|
|
||||||
|
|
||||||
/* async drv <--> lib comms */
|
|
||||||
|
|
||||||
struct fpi_ssm;
|
|
||||||
typedef void (*ssm_completed_fn)(struct fpi_ssm *ssm);
|
|
||||||
typedef void (*ssm_handler_fn)(struct fpi_ssm *ssm);
|
|
||||||
|
|
||||||
/* sequential state machine: state machine that iterates sequentially over
|
|
||||||
* a predefined series of states. can be aborted by either completion or
|
|
||||||
* abortion error conditions. */
|
|
||||||
struct fpi_ssm {
|
|
||||||
struct fp_dev *dev;
|
|
||||||
struct fpi_ssm *parentsm;
|
|
||||||
void *priv;
|
|
||||||
int nr_states;
|
|
||||||
int cur_state;
|
|
||||||
gboolean completed;
|
|
||||||
int error;
|
|
||||||
ssm_completed_fn callback;
|
|
||||||
ssm_handler_fn handler;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/* for library and drivers */
|
|
||||||
struct fpi_ssm *fpi_ssm_new(struct fp_dev *dev, ssm_handler_fn handler,
|
|
||||||
int nr_states);
|
|
||||||
void fpi_ssm_free(struct fpi_ssm *machine);
|
|
||||||
void fpi_ssm_start(struct fpi_ssm *machine, ssm_completed_fn callback);
|
|
||||||
void fpi_ssm_start_subsm(struct fpi_ssm *parent, struct fpi_ssm *child);
|
|
||||||
int fpi_ssm_has_completed(struct fpi_ssm *machine);
|
|
||||||
|
|
||||||
/* for drivers */
|
|
||||||
void fpi_ssm_next_state(struct fpi_ssm *machine);
|
|
||||||
void fpi_ssm_jump_to_state(struct fpi_ssm *machine, int state);
|
|
||||||
void fpi_ssm_mark_completed(struct fpi_ssm *machine);
|
|
||||||
void fpi_ssm_mark_aborted(struct fpi_ssm *machine, int error);
|
|
||||||
|
|
||||||
void fpi_drvcb_open_complete(struct fp_dev *dev, int status);
|
|
||||||
void fpi_drvcb_close_complete(struct fp_dev *dev);
|
|
||||||
|
|
||||||
void fpi_drvcb_enroll_started(struct fp_dev *dev, int status);
|
|
||||||
void fpi_drvcb_enroll_stage_completed(struct fp_dev *dev, int result,
|
|
||||||
struct fp_print_data *data, struct fp_img *img);
|
|
||||||
void fpi_drvcb_enroll_stopped(struct fp_dev *dev);
|
|
||||||
|
|
||||||
void fpi_drvcb_verify_started(struct fp_dev *dev, int status);
|
|
||||||
void fpi_drvcb_report_verify_result(struct fp_dev *dev, int result,
|
|
||||||
struct fp_img *img);
|
struct fp_img *img);
|
||||||
void fpi_drvcb_verify_stopped(struct fp_dev *dev);
|
void fpi_drvcb_capture_stopped(struct fp_dev *dev);
|
||||||
|
|
||||||
void fpi_drvcb_identify_started(struct fp_dev *dev, int status);
|
void fpi_drvcb_identify_started(struct fp_dev *dev, int status);
|
||||||
void fpi_drvcb_report_identify_result(struct fp_dev *dev, int result,
|
void fpi_drvcb_report_identify_result(struct fp_dev *dev, int result,
|
||||||
size_t match_offset, struct fp_img *img);
|
size_t match_offset, struct fp_img *img);
|
||||||
void fpi_drvcb_identify_stopped(struct fp_dev *dev);
|
void fpi_drvcb_identify_stopped(struct fp_dev *dev);
|
||||||
|
|
||||||
void fpi_drvcb_capture_started(struct fp_dev *dev, int status);
|
#include "drivers_definitions.h"
|
||||||
void fpi_drvcb_report_capture_result(struct fp_dev *dev, int result,
|
|
||||||
struct fp_img *img);
|
|
||||||
void fpi_drvcb_capture_stopped(struct fp_dev *dev);
|
|
||||||
|
|
||||||
/* for image drivers */
|
|
||||||
void fpi_imgdev_open_complete(struct fp_img_dev *imgdev, int status);
|
|
||||||
void fpi_imgdev_close_complete(struct fp_img_dev *imgdev);
|
|
||||||
void fpi_imgdev_activate_complete(struct fp_img_dev *imgdev, int status);
|
|
||||||
void fpi_imgdev_deactivate_complete(struct fp_img_dev *imgdev);
|
|
||||||
void fpi_imgdev_report_finger_status(struct fp_img_dev *imgdev,
|
|
||||||
gboolean present);
|
|
||||||
void fpi_imgdev_image_captured(struct fp_img_dev *imgdev, struct fp_img *img);
|
|
||||||
void fpi_imgdev_session_error(struct fp_img_dev *imgdev, int error);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
487
libfprint/fpi-assembling.c
Normal file
487
libfprint/fpi-assembling.c
Normal file
@@ -0,0 +1,487 @@
|
|||||||
|
/*
|
||||||
|
* 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 "fpi-assembling.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SECTION:fpi-assembling
|
||||||
|
* @title: Image frame assembly
|
||||||
|
* @short_description: Image frame assembly helpers
|
||||||
|
*
|
||||||
|
* Those are the helpers to manipulate capture data from fingerprint readers
|
||||||
|
* into a uniform image that can be further processed. This is usually used
|
||||||
|
* by drivers for devices which have a small sensor and thus need to capture
|
||||||
|
* data in small stripes.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_do_movement_estimation:
|
||||||
|
* @ctx: #fpi_frame_asmbl_ctx - frame assembling context
|
||||||
|
* @stripes: a singly-linked list of #fpi_frame
|
||||||
|
* @num_stripes: number of items in @stripes to process
|
||||||
|
*
|
||||||
|
* fpi_do_movement_estimation() estimates the movement between adjacent
|
||||||
|
* frames, populating @delta_x and @delta_y values for each #fpi_frame.
|
||||||
|
*
|
||||||
|
* This function is used for devices that don't do movement estimation
|
||||||
|
* in hardware. If hardware movement estimation is supported, the driver
|
||||||
|
* should populate @delta_x and @delta_y instead.
|
||||||
|
*
|
||||||
|
* Note that @num_stripes might be shorter than the length of the list,
|
||||||
|
* if some stripes should be skipped.
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_assemble_frames:
|
||||||
|
* @ctx: #fpi_frame_asmbl_ctx - frame assembling context
|
||||||
|
* @stripes: linked list of #fpi_frame
|
||||||
|
* @num_stripes: number of items in @stripes to process
|
||||||
|
*
|
||||||
|
* fpi_assemble_frames() assembles individual frames into a single image.
|
||||||
|
* It expects @delta_x and @delta_y of #fpi_frame to be populated.
|
||||||
|
*
|
||||||
|
* Note that @num_stripes might be shorter than the length of the list,
|
||||||
|
* if some stripes should be skipped.
|
||||||
|
*
|
||||||
|
* Returns: a newly allocated #fp_img.
|
||||||
|
*/
|
||||||
|
struct fp_img *fpi_assemble_frames(struct fpi_frame_asmbl_ctx *ctx,
|
||||||
|
GSList *stripes, size_t num_stripes)
|
||||||
|
{
|
||||||
|
GSList *stripe;
|
||||||
|
struct fp_img *img;
|
||||||
|
int height = 0;
|
||||||
|
int i, y, x;
|
||||||
|
gboolean reverse = FALSE;
|
||||||
|
struct fpi_frame *fpi_frame;
|
||||||
|
|
||||||
|
//FIXME g_return_if_fail
|
||||||
|
BUG_ON(num_stripes == 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 < num_stripes);
|
||||||
|
|
||||||
|
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 < num_stripes);
|
||||||
|
|
||||||
|
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;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_assemble_lines:
|
||||||
|
* @ctx: #fpi_frame_asmbl_ctx - frame assembling context
|
||||||
|
* @lines: linked list of lines
|
||||||
|
* @num_lines: number of items in @lines to process
|
||||||
|
*
|
||||||
|
* #fpi_assemble_lines assembles individual lines into a single image.
|
||||||
|
* It also rescales image to account variable swiping speed.
|
||||||
|
*
|
||||||
|
* Note that @num_lines might be shorter than the length of the list,
|
||||||
|
* if some lines should be skipped.
|
||||||
|
*
|
||||||
|
* Returns: a newly allocated #fp_img.
|
||||||
|
*/
|
||||||
|
struct fp_img *fpi_assemble_lines(struct fpi_line_asmbl_ctx *ctx,
|
||||||
|
GSList *lines, size_t num_lines)
|
||||||
|
{
|
||||||
|
/* 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((num_lines / 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 (num_lines >= 2, NULL);
|
||||||
|
|
||||||
|
fp_dbg("%"G_GINT64_FORMAT, g_get_real_time());
|
||||||
|
|
||||||
|
row1 = lines;
|
||||||
|
for (i = 0; (i < num_lines - 1) && row1; i += 2) {
|
||||||
|
int bestmatch = i;
|
||||||
|
int bestdiff = 0;
|
||||||
|
int j, firstrow, lastrow;
|
||||||
|
|
||||||
|
firstrow = i + 1;
|
||||||
|
lastrow = MIN(i + ctx->max_search_offset, num_lines - 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, (num_lines / 2) - 1, ctx->median_filter_size);
|
||||||
|
|
||||||
|
fp_dbg("offsets_filtered: %"G_GINT64_FORMAT, g_get_real_time());
|
||||||
|
for (i = 0; i <= (num_lines / 2) - 1; i++)
|
||||||
|
fp_dbg("%d", offsets[i]);
|
||||||
|
row1 = lines;
|
||||||
|
for (i = 0; i < num_lines - 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;
|
||||||
|
memmove(img->data, output, ctx->line_width * line_ind);
|
||||||
|
g_free(offsets);
|
||||||
|
g_free(output);
|
||||||
|
return img;
|
||||||
|
}
|
||||||
115
libfprint/fpi-assembling.h
Normal file
115
libfprint/fpi-assembling.h
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
* 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 __FPI_ASSEMBLING_H__
|
||||||
|
#define __FPI_ASSEMBLING_H__
|
||||||
|
|
||||||
|
#include <fprint.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_frame:
|
||||||
|
* @delta_x: X offset of the frame
|
||||||
|
* @delta_y: Y offset of the frame
|
||||||
|
* @data: bitmap
|
||||||
|
*
|
||||||
|
* #fpi_frame is used to store frames for swipe sensors. Drivers should
|
||||||
|
* populate delta_x and delta_y if the device supports hardware movement
|
||||||
|
* estimation.
|
||||||
|
*/
|
||||||
|
struct fpi_frame {
|
||||||
|
int delta_x;
|
||||||
|
int delta_y;
|
||||||
|
unsigned char data[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_frame_asmbl_ctx:
|
||||||
|
* @frame_width: width of the frame
|
||||||
|
* @frame_height: height of the frame
|
||||||
|
* @image_width: resulting image width
|
||||||
|
* @get_pixel: pixel accessor, returns pixel brightness at x,y of frame
|
||||||
|
*
|
||||||
|
* #fpi_frame_asmbl_ctx is a structure holding the context for frame
|
||||||
|
* assembling routines.
|
||||||
|
*
|
||||||
|
* Drivers should define their own #fpi_frame_asmbl_ctx depending on
|
||||||
|
* hardware parameters of scanner. @image_width is usually 25% wider than
|
||||||
|
* @frame_width to take horizontal movement into account.
|
||||||
|
*/
|
||||||
|
struct fpi_frame_asmbl_ctx {
|
||||||
|
unsigned int frame_width;
|
||||||
|
unsigned int frame_height;
|
||||||
|
unsigned int image_width;
|
||||||
|
unsigned char (*get_pixel)(struct fpi_frame_asmbl_ctx *ctx,
|
||||||
|
struct fpi_frame *frame,
|
||||||
|
unsigned int x,
|
||||||
|
unsigned int y);
|
||||||
|
};
|
||||||
|
|
||||||
|
void fpi_do_movement_estimation(struct fpi_frame_asmbl_ctx *ctx,
|
||||||
|
GSList *stripes, size_t num_stripes);
|
||||||
|
|
||||||
|
struct fp_img *fpi_assemble_frames(struct fpi_frame_asmbl_ctx *ctx,
|
||||||
|
GSList *stripes, size_t num_stripes);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_line_asmbl_ctx:
|
||||||
|
* @line_width: width of line
|
||||||
|
* @max_height: maximal height of assembled image
|
||||||
|
* @resolution: scale factor used for line assembling routines.
|
||||||
|
* @median_filter_size: size of median filter for movement estimation
|
||||||
|
* @max_search_offset: the number of lines to search for the next line
|
||||||
|
* @get_deviation: pointer to a function that returns the numerical difference
|
||||||
|
* between two lines
|
||||||
|
* @get_pixel: pixel accessor, returns pixel brightness at x of line
|
||||||
|
*
|
||||||
|
* #fpi_line_asmbl_ctx is a structure holding the context for line assembling
|
||||||
|
* routines.
|
||||||
|
*
|
||||||
|
* Drivers should define their own #fpi_line_asmbl_ctx depending on
|
||||||
|
* the hardware parameters of the scanner. Swipe scanners of this type usually
|
||||||
|
* return two lines, the second line is often narrower than first and is used
|
||||||
|
* for movement estimation.
|
||||||
|
*
|
||||||
|
* The @max_search_offset value indicates how many lines forward the assembling
|
||||||
|
* routines should look while searching for next line. This value depends on
|
||||||
|
* how fast the hardware sends frames.
|
||||||
|
*
|
||||||
|
* The function pointed to by @get_deviation should return the numerical difference
|
||||||
|
* between two lines. Higher values means lines are more different. If the reader
|
||||||
|
* returns two lines at a time, this function should be used to estimate the
|
||||||
|
* difference between pairs of lines.
|
||||||
|
*/
|
||||||
|
struct fpi_line_asmbl_ctx {
|
||||||
|
unsigned int line_width;
|
||||||
|
unsigned int max_height;
|
||||||
|
unsigned int resolution;
|
||||||
|
unsigned int median_filter_size;
|
||||||
|
unsigned int 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 int x);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fp_img *fpi_assemble_lines(struct fpi_line_asmbl_ctx *ctx,
|
||||||
|
GSList *lines, size_t num_lines);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -19,11 +19,21 @@
|
|||||||
|
|
||||||
#define FP_COMPONENT "async"
|
#define FP_COMPONENT "async"
|
||||||
|
|
||||||
|
#include "fp_internal.h"
|
||||||
|
#include "fpi-async.h"
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
|
||||||
#include "fp_internal.h"
|
/*
|
||||||
|
* SECTION:fpi-async
|
||||||
|
* @title: Asynchronous operations reporting
|
||||||
|
* @short_description: Asynchronous operations reporting functions
|
||||||
|
*
|
||||||
|
* Those functions are used by primitive drivers to report back their
|
||||||
|
* current status. Most drivers, imaging ones, do not need to use them.
|
||||||
|
*/
|
||||||
|
|
||||||
/* Drivers call this when device initialisation has completed */
|
/* Drivers call this when device initialisation has completed */
|
||||||
void fpi_drvcb_open_complete(struct fp_dev *dev, int status)
|
void fpi_drvcb_open_complete(struct fp_dev *dev, int status)
|
||||||
@@ -36,15 +46,35 @@ void fpi_drvcb_open_complete(struct fp_dev *dev, int status)
|
|||||||
dev->open_cb(dev, status, dev->open_cb_data);
|
dev->open_cb(dev, status, dev->open_cb_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
API_EXPORTED int fp_async_dev_open(struct fp_dscv_dev *ddev, fp_dev_open_cb cb,
|
/**
|
||||||
|
* fp_async_dev_open:
|
||||||
|
* @ddev: the struct #fp_dscv_dev discovered device to open
|
||||||
|
* @callback: the callback to call when the device has been opened
|
||||||
|
* @user_data: user data to pass to the callback
|
||||||
|
*
|
||||||
|
* Opens and initialises a device. This is the function you call in order
|
||||||
|
* to convert a #fp_dscv_dev discovered device into an actual device handle
|
||||||
|
* that you can perform operations with.
|
||||||
|
*
|
||||||
|
* The error status of the opening will be provided as an argument to the
|
||||||
|
* #fp_dev_open_cb callback.
|
||||||
|
*
|
||||||
|
* Returns: 0 on success, non-zero on error
|
||||||
|
*/
|
||||||
|
API_EXPORTED int fp_async_dev_open(struct fp_dscv_dev *ddev, fp_dev_open_cb callback,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_driver *drv = ddev->drv;
|
struct fp_driver *drv;
|
||||||
struct fp_dev *dev;
|
struct fp_dev *dev;
|
||||||
libusb_device_handle *udevh;
|
libusb_device_handle *udevh;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
fp_dbg("");
|
g_return_val_if_fail(ddev != NULL, -ENODEV);
|
||||||
|
g_return_val_if_fail (callback != NULL, -EINVAL);
|
||||||
|
|
||||||
|
drv = ddev->drv;
|
||||||
|
|
||||||
|
G_DEBUG_HERE();
|
||||||
r = libusb_open(ddev->udev, &udevh);
|
r = libusb_open(ddev->udev, &udevh);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
fp_err("usb_open failed, error %d", r);
|
fp_err("usb_open failed, error %d", r);
|
||||||
@@ -56,7 +86,7 @@ API_EXPORTED int fp_async_dev_open(struct fp_dscv_dev *ddev, fp_dev_open_cb cb,
|
|||||||
dev->udev = udevh;
|
dev->udev = udevh;
|
||||||
dev->__enroll_stage = -1;
|
dev->__enroll_stage = -1;
|
||||||
dev->state = DEV_STATE_INITIALIZING;
|
dev->state = DEV_STATE_INITIALIZING;
|
||||||
dev->open_cb = cb;
|
dev->open_cb = callback;
|
||||||
dev->open_cb_data = user_data;
|
dev->open_cb_data = user_data;
|
||||||
|
|
||||||
if (!drv->open) {
|
if (!drv->open) {
|
||||||
@@ -78,19 +108,35 @@ API_EXPORTED int fp_async_dev_open(struct fp_dscv_dev *ddev, fp_dev_open_cb cb,
|
|||||||
/* Drivers call this when device deinitialisation has completed */
|
/* Drivers call this when device deinitialisation has completed */
|
||||||
void fpi_drvcb_close_complete(struct fp_dev *dev)
|
void fpi_drvcb_close_complete(struct fp_dev *dev)
|
||||||
{
|
{
|
||||||
fp_dbg("");
|
G_DEBUG_HERE();
|
||||||
BUG_ON(dev->state != DEV_STATE_DEINITIALIZING);
|
BUG_ON(dev->state != DEV_STATE_DEINITIALIZING);
|
||||||
dev->state = DEV_STATE_DEINITIALIZED;
|
dev->state = DEV_STATE_DEINITIALIZED;
|
||||||
|
fpi_timeout_cancel_all_for_dev(dev);
|
||||||
libusb_close(dev->udev);
|
libusb_close(dev->udev);
|
||||||
if (dev->close_cb)
|
if (dev->close_cb)
|
||||||
dev->close_cb(dev, dev->close_cb_data);
|
dev->close_cb(dev, dev->close_cb_data);
|
||||||
g_free(dev);
|
g_free(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fp_async_dev_close:
|
||||||
|
* @dev: the struct #fp_dev device
|
||||||
|
* @callback: the callback to call when the device has been closed
|
||||||
|
* @user_data: user data to pass to the callback
|
||||||
|
*
|
||||||
|
* Closes a device. You must call this function when you have finished using
|
||||||
|
* a fingerprint device.
|
||||||
|
*/
|
||||||
API_EXPORTED void fp_async_dev_close(struct fp_dev *dev,
|
API_EXPORTED void fp_async_dev_close(struct fp_dev *dev,
|
||||||
fp_dev_close_cb callback, void *user_data)
|
fp_operation_stop_cb callback, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_driver *drv = dev->drv;
|
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)
|
if (g_slist_index(opened_devices, (gconstpointer) dev) == -1)
|
||||||
fp_err("device %p not in opened list!", dev);
|
fp_err("device %p not in opened list!", dev);
|
||||||
@@ -98,12 +144,6 @@ API_EXPORTED void fp_async_dev_close(struct fp_dev *dev,
|
|||||||
|
|
||||||
dev->close_cb = callback;
|
dev->close_cb = callback;
|
||||||
dev->close_cb_data = user_data;
|
dev->close_cb_data = user_data;
|
||||||
|
|
||||||
if (!drv->close) {
|
|
||||||
fpi_drvcb_close_complete(dev);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev->state = DEV_STATE_DEINITIALIZING;
|
dev->state = DEV_STATE_DEINITIALIZING;
|
||||||
drv->close(dev);
|
drv->close(dev);
|
||||||
}
|
}
|
||||||
@@ -127,12 +167,29 @@ void fpi_drvcb_enroll_started(struct fp_dev *dev, int status)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fp_async_enroll_start:
|
||||||
|
* @dev: the struct #fp_dev device
|
||||||
|
* @callback: the callback to call for each stage of the enrollment
|
||||||
|
* @user_data: user data to pass to the callback
|
||||||
|
*
|
||||||
|
* Starts an enrollment and calls @callback for each enrollment stage.
|
||||||
|
* See [Enrolling](libfprint-Devices-operations.html#enrolling)
|
||||||
|
* for an explanation of enroll stages.
|
||||||
|
*
|
||||||
|
* Returns: 0 on success, non-zero on error
|
||||||
|
*/
|
||||||
API_EXPORTED int fp_async_enroll_start(struct fp_dev *dev,
|
API_EXPORTED int fp_async_enroll_start(struct fp_dev *dev,
|
||||||
fp_enroll_stage_cb callback, void *user_data)
|
fp_enroll_stage_cb callback, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_driver *drv = dev->drv;
|
struct fp_driver *drv;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
g_return_val_if_fail(dev != NULL, -ENODEV);
|
||||||
|
g_return_val_if_fail (callback != NULL, -EINVAL);
|
||||||
|
|
||||||
|
drv = dev->drv;
|
||||||
|
|
||||||
if (!dev->nr_enroll_stages || !drv->enroll_start) {
|
if (!dev->nr_enroll_stages || !drv->enroll_start) {
|
||||||
fp_err("driver %s has 0 enroll stages or no enroll func",
|
fp_err("driver %s has 0 enroll stages or no enroll func",
|
||||||
drv->name);
|
drv->name);
|
||||||
@@ -174,20 +231,34 @@ void fpi_drvcb_enroll_stage_completed(struct fp_dev *dev, int result,
|
|||||||
/* Drivers call this when enrollment has stopped */
|
/* Drivers call this when enrollment has stopped */
|
||||||
void fpi_drvcb_enroll_stopped(struct fp_dev *dev)
|
void fpi_drvcb_enroll_stopped(struct fp_dev *dev)
|
||||||
{
|
{
|
||||||
fp_dbg("");
|
G_DEBUG_HERE();
|
||||||
BUG_ON(dev->state != DEV_STATE_ENROLL_STOPPING);
|
BUG_ON(dev->state != DEV_STATE_ENROLL_STOPPING);
|
||||||
dev->state = DEV_STATE_INITIALIZED;
|
dev->state = DEV_STATE_INITIALIZED;
|
||||||
if (dev->enroll_stop_cb)
|
if (dev->enroll_stop_cb)
|
||||||
dev->enroll_stop_cb(dev, dev->enroll_stop_cb_data);
|
dev->enroll_stop_cb(dev, dev->enroll_stop_cb_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fp_async_enroll_stop:
|
||||||
|
* @dev: the struct #fp_dev device
|
||||||
|
* @callback: the callback to call when the enrollment has been cancelled
|
||||||
|
* @user_data: user data to pass to the callback
|
||||||
|
*
|
||||||
|
* Stops an ongoing enrollment started with fp_async_enroll_start().
|
||||||
|
*
|
||||||
|
* Returns: 0 on success, non-zero on error
|
||||||
|
*/
|
||||||
API_EXPORTED int fp_async_enroll_stop(struct fp_dev *dev,
|
API_EXPORTED int fp_async_enroll_stop(struct fp_dev *dev,
|
||||||
fp_enroll_stop_cb callback, void *user_data)
|
fp_operation_stop_cb callback, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_driver *drv = dev->drv;
|
struct fp_driver *drv;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
fp_dbg("");
|
g_return_val_if_fail(dev != NULL, -ENODEV);
|
||||||
|
|
||||||
|
drv = dev->drv;
|
||||||
|
|
||||||
|
G_DEBUG_HERE();
|
||||||
if (!drv->enroll_start)
|
if (!drv->enroll_start)
|
||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
|
|
||||||
@@ -210,13 +281,32 @@ API_EXPORTED int fp_async_enroll_stop(struct fp_dev *dev,
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fp_async_verify_start:
|
||||||
|
* @dev: the struct #fp_dev device
|
||||||
|
* @data: the print to verify against. Must have been previously
|
||||||
|
* enrolled with a device compatible to the device selected to perform the scan
|
||||||
|
* @callback: the callback to call when the verification has finished
|
||||||
|
* @user_data: user data to pass to the callback
|
||||||
|
*
|
||||||
|
* Starts a verification and calls @callback when the verification has
|
||||||
|
* finished. See fp_verify_finger_img() for the synchronous API. When the
|
||||||
|
* @callback has been called, you must call fp_async_verify_stop().
|
||||||
|
*
|
||||||
|
* Returns: 0 on success, non-zero on error
|
||||||
|
*/
|
||||||
API_EXPORTED int fp_async_verify_start(struct fp_dev *dev,
|
API_EXPORTED int fp_async_verify_start(struct fp_dev *dev,
|
||||||
struct fp_print_data *data, fp_verify_cb callback, void *user_data)
|
struct fp_print_data *data, fp_img_operation_cb callback, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_driver *drv = dev->drv;
|
struct fp_driver *drv;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
fp_dbg("");
|
g_return_val_if_fail(dev != NULL, -ENODEV);
|
||||||
|
g_return_val_if_fail (callback != NULL, -EINVAL);
|
||||||
|
|
||||||
|
drv = dev->drv;
|
||||||
|
|
||||||
|
G_DEBUG_HERE();
|
||||||
if (!drv->verify_start)
|
if (!drv->verify_start)
|
||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
|
|
||||||
@@ -237,7 +327,7 @@ API_EXPORTED int fp_async_verify_start(struct fp_dev *dev,
|
|||||||
/* Drivers call this when verification has started */
|
/* Drivers call this when verification has started */
|
||||||
void fpi_drvcb_verify_started(struct fp_dev *dev, int status)
|
void fpi_drvcb_verify_started(struct fp_dev *dev, int status)
|
||||||
{
|
{
|
||||||
fp_dbg("");
|
G_DEBUG_HERE();
|
||||||
BUG_ON(dev->state != DEV_STATE_VERIFY_STARTING);
|
BUG_ON(dev->state != DEV_STATE_VERIFY_STARTING);
|
||||||
if (status) {
|
if (status) {
|
||||||
if (status > 0) {
|
if (status > 0) {
|
||||||
@@ -271,21 +361,47 @@ void fpi_drvcb_report_verify_result(struct fp_dev *dev, int result,
|
|||||||
/* Drivers call this when verification has stopped */
|
/* Drivers call this when verification has stopped */
|
||||||
void fpi_drvcb_verify_stopped(struct fp_dev *dev)
|
void fpi_drvcb_verify_stopped(struct fp_dev *dev)
|
||||||
{
|
{
|
||||||
fp_dbg("");
|
G_DEBUG_HERE();
|
||||||
BUG_ON(dev->state != DEV_STATE_VERIFY_STOPPING);
|
BUG_ON(dev->state != DEV_STATE_VERIFY_STOPPING);
|
||||||
dev->state = DEV_STATE_INITIALIZED;
|
dev->state = DEV_STATE_INITIALIZED;
|
||||||
if (dev->verify_stop_cb)
|
if (dev->verify_stop_cb)
|
||||||
dev->verify_stop_cb(dev, dev->verify_stop_cb_data);
|
dev->verify_stop_cb(dev, dev->verify_stop_cb_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fp_async_verify_stop:
|
||||||
|
* @dev: the struct #fp_dev device
|
||||||
|
* @callback: the callback to call to finish a verification
|
||||||
|
* @user_data: user data to pass to the callback
|
||||||
|
*
|
||||||
|
* Finishes an ongoing verification started with fp_async_verify_start().
|
||||||
|
*
|
||||||
|
* Returns: 0 on success, non-zero on error
|
||||||
|
*/
|
||||||
API_EXPORTED int fp_async_verify_stop(struct fp_dev *dev,
|
API_EXPORTED int fp_async_verify_stop(struct fp_dev *dev,
|
||||||
fp_verify_stop_cb callback, void *user_data)
|
fp_operation_stop_cb callback, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_driver *drv = dev->drv;
|
struct fp_driver *drv;
|
||||||
gboolean iterating = (dev->state == DEV_STATE_VERIFYING);
|
gboolean iterating = (dev->state == DEV_STATE_VERIFYING);
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
fp_dbg("");
|
g_return_val_if_fail(dev != NULL, -ENODEV);
|
||||||
|
|
||||||
|
G_DEBUG_HERE();
|
||||||
|
|
||||||
|
if (dev->state == DEV_STATE_VERIFY_STOPPING) {
|
||||||
|
fp_dbg ("Already stopping verification, returning -EINPROGRESS");
|
||||||
|
return -EINPROGRESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dev->state == DEV_STATE_INITIALIZED) {
|
||||||
|
if (callback)
|
||||||
|
callback(dev, user_data);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
drv = dev->drv;
|
||||||
|
|
||||||
BUG_ON(dev->state != DEV_STATE_ERROR
|
BUG_ON(dev->state != DEV_STATE_ERROR
|
||||||
&& dev->state != DEV_STATE_VERIFYING
|
&& dev->state != DEV_STATE_VERIFYING
|
||||||
&& dev->state != DEV_STATE_VERIFY_DONE);
|
&& dev->state != DEV_STATE_VERIFY_DONE);
|
||||||
@@ -311,13 +427,32 @@ API_EXPORTED int fp_async_verify_stop(struct fp_dev *dev,
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fp_async_identify_start:
|
||||||
|
* @dev: the struct #fp_dev device
|
||||||
|
* @gallery: NULL-terminated array of pointers to the prints to
|
||||||
|
* identify against. Each one must have been previously enrolled with a device
|
||||||
|
* compatible to the device selected to perform the scan
|
||||||
|
* @callback: the callback to call when the identification has finished
|
||||||
|
* @user_data: user data to pass to the callback
|
||||||
|
*
|
||||||
|
* Performs a new scan and verifies it against a previously enrolled print.
|
||||||
|
* See also: fp_verify_finger_img()
|
||||||
|
*
|
||||||
|
* Returns: 0 on success, non-zero on error
|
||||||
|
*/
|
||||||
API_EXPORTED int fp_async_identify_start(struct fp_dev *dev,
|
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_print_data **gallery, fp_identify_cb callback, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_driver *drv = dev->drv;
|
struct fp_driver *drv;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
fp_dbg("");
|
g_return_val_if_fail(dev != NULL, -ENODEV);
|
||||||
|
g_return_val_if_fail (callback != NULL, -EINVAL);
|
||||||
|
|
||||||
|
drv = dev->drv;
|
||||||
|
|
||||||
|
G_DEBUG_HERE();
|
||||||
if (!drv->identify_start)
|
if (!drv->identify_start)
|
||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
dev->state = DEV_STATE_IDENTIFY_STARTING;
|
dev->state = DEV_STATE_IDENTIFY_STARTING;
|
||||||
@@ -369,14 +504,40 @@ void fpi_drvcb_report_identify_result(struct fp_dev *dev, int result,
|
|||||||
fp_dbg("ignoring verify result as no callback is subscribed");
|
fp_dbg("ignoring verify result as no callback is subscribed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fp_async_identify_stop:
|
||||||
|
* @dev: the struct #fp_dev device
|
||||||
|
* @callback: the callback to call when the identification has stopped
|
||||||
|
* @user_data: user data to pass to the callback
|
||||||
|
*
|
||||||
|
* Stops an ongoing identification started with fp_async_identify_start().
|
||||||
|
*
|
||||||
|
* Returns: 0 on success, non-zero on error
|
||||||
|
*/
|
||||||
API_EXPORTED int fp_async_identify_stop(struct fp_dev *dev,
|
API_EXPORTED int fp_async_identify_stop(struct fp_dev *dev,
|
||||||
fp_identify_stop_cb callback, void *user_data)
|
fp_operation_stop_cb callback, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_driver *drv = dev->drv;
|
struct fp_driver *drv;
|
||||||
gboolean iterating = (dev->state == DEV_STATE_IDENTIFYING);
|
gboolean iterating = (dev->state == DEV_STATE_IDENTIFYING);
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
fp_dbg("");
|
g_return_val_if_fail(dev != NULL, -ENODEV);
|
||||||
|
|
||||||
|
G_DEBUG_HERE();
|
||||||
|
|
||||||
|
if (dev->state == DEV_STATE_IDENTIFY_STOPPING) {
|
||||||
|
fp_dbg ("Already stopping identification, returning -EINPROGRESS");
|
||||||
|
return -EINPROGRESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dev->state == DEV_STATE_INITIALIZED) {
|
||||||
|
if (callback)
|
||||||
|
callback(dev, user_data);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
drv = dev->drv;
|
||||||
|
|
||||||
BUG_ON(dev->state != DEV_STATE_IDENTIFYING
|
BUG_ON(dev->state != DEV_STATE_IDENTIFYING
|
||||||
&& dev->state != DEV_STATE_IDENTIFY_DONE);
|
&& dev->state != DEV_STATE_IDENTIFY_DONE);
|
||||||
|
|
||||||
@@ -405,20 +566,39 @@ API_EXPORTED int fp_async_identify_stop(struct fp_dev *dev,
|
|||||||
/* Drivers call this when identification has stopped */
|
/* Drivers call this when identification has stopped */
|
||||||
void fpi_drvcb_identify_stopped(struct fp_dev *dev)
|
void fpi_drvcb_identify_stopped(struct fp_dev *dev)
|
||||||
{
|
{
|
||||||
fp_dbg("");
|
G_DEBUG_HERE();
|
||||||
BUG_ON(dev->state != DEV_STATE_IDENTIFY_STOPPING);
|
BUG_ON(dev->state != DEV_STATE_IDENTIFY_STOPPING);
|
||||||
dev->state = DEV_STATE_INITIALIZED;
|
dev->state = DEV_STATE_INITIALIZED;
|
||||||
if (dev->identify_stop_cb)
|
if (dev->identify_stop_cb)
|
||||||
dev->identify_stop_cb(dev, dev->identify_stop_cb_data);
|
dev->identify_stop_cb(dev, dev->identify_stop_cb_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fp_async_capture_start:
|
||||||
|
* @dev: the struct #fp_dev device
|
||||||
|
* @unconditional: whether to unconditionally capture an image, or to only capture when a finger is detected
|
||||||
|
* @callback: the callback to call when the capture has finished
|
||||||
|
* @user_data: user data to pass to the callback
|
||||||
|
*
|
||||||
|
* Start the capture of an #fp_img from a device. When the @callback has been called,
|
||||||
|
* you must call fp_async_capture_stop().
|
||||||
|
*
|
||||||
|
* Returns: 0 on success, non-zero on error. -ENOTSUP indicates that either the
|
||||||
|
* @unconditional flag was set but the device does not support this, or that the•
|
||||||
|
* device does not support imaging
|
||||||
|
*/
|
||||||
API_EXPORTED int fp_async_capture_start(struct fp_dev *dev, int unconditional,
|
API_EXPORTED int fp_async_capture_start(struct fp_dev *dev, int unconditional,
|
||||||
fp_capture_cb callback, void *user_data)
|
fp_img_operation_cb callback, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_driver *drv = dev->drv;
|
struct fp_driver *drv;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
fp_dbg("");
|
g_return_val_if_fail(dev != NULL, -ENODEV);
|
||||||
|
g_return_val_if_fail (callback != NULL, -EINVAL);
|
||||||
|
|
||||||
|
drv = dev->drv;
|
||||||
|
|
||||||
|
G_DEBUG_HERE();
|
||||||
if (!drv->capture_start)
|
if (!drv->capture_start)
|
||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
|
|
||||||
@@ -431,7 +611,7 @@ API_EXPORTED int fp_async_capture_start(struct fp_dev *dev, int unconditional,
|
|||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
dev->capture_cb = NULL;
|
dev->capture_cb = NULL;
|
||||||
dev->state = DEV_STATE_ERROR;
|
dev->state = DEV_STATE_ERROR;
|
||||||
fp_err("failed to start verification, error %d", r);
|
fp_err("failed to start capture, error %d", r);
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
@@ -439,7 +619,7 @@ API_EXPORTED int fp_async_capture_start(struct fp_dev *dev, int unconditional,
|
|||||||
/* Drivers call this when capture has started */
|
/* Drivers call this when capture has started */
|
||||||
void fpi_drvcb_capture_started(struct fp_dev *dev, int status)
|
void fpi_drvcb_capture_started(struct fp_dev *dev, int status)
|
||||||
{
|
{
|
||||||
fp_dbg("");
|
G_DEBUG_HERE();
|
||||||
BUG_ON(dev->state != DEV_STATE_CAPTURE_STARTING);
|
BUG_ON(dev->state != DEV_STATE_CAPTURE_STARTING);
|
||||||
if (status) {
|
if (status) {
|
||||||
if (status > 0) {
|
if (status > 0) {
|
||||||
@@ -472,20 +652,34 @@ void fpi_drvcb_report_capture_result(struct fp_dev *dev, int result,
|
|||||||
/* Drivers call this when capture has stopped */
|
/* Drivers call this when capture has stopped */
|
||||||
void fpi_drvcb_capture_stopped(struct fp_dev *dev)
|
void fpi_drvcb_capture_stopped(struct fp_dev *dev)
|
||||||
{
|
{
|
||||||
fp_dbg("");
|
G_DEBUG_HERE();
|
||||||
BUG_ON(dev->state != DEV_STATE_CAPTURE_STOPPING);
|
BUG_ON(dev->state != DEV_STATE_CAPTURE_STOPPING);
|
||||||
dev->state = DEV_STATE_INITIALIZED;
|
dev->state = DEV_STATE_INITIALIZED;
|
||||||
if (dev->capture_stop_cb)
|
if (dev->capture_stop_cb)
|
||||||
dev->capture_stop_cb(dev, dev->capture_stop_cb_data);
|
dev->capture_stop_cb(dev, dev->capture_stop_cb_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fp_async_capture_stop:
|
||||||
|
* @dev: the struct #fp_dev device
|
||||||
|
* @callback: the callback to call when the capture has been stopped
|
||||||
|
* @user_data: user data to pass to the callback
|
||||||
|
*
|
||||||
|
* Stops an ongoing verification started with fp_async_capture_start().
|
||||||
|
*
|
||||||
|
* Returns: 0 on success, non-zero on error
|
||||||
|
*/
|
||||||
API_EXPORTED int fp_async_capture_stop(struct fp_dev *dev,
|
API_EXPORTED int fp_async_capture_stop(struct fp_dev *dev,
|
||||||
fp_capture_stop_cb callback, void *user_data)
|
fp_operation_stop_cb callback, void *user_data)
|
||||||
{
|
{
|
||||||
struct fp_driver *drv = dev->drv;
|
struct fp_driver *drv;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
fp_dbg("");
|
g_return_val_if_fail(dev != NULL, -ENODEV);
|
||||||
|
|
||||||
|
drv = dev->drv;
|
||||||
|
|
||||||
|
G_DEBUG_HERE();
|
||||||
BUG_ON(dev->state != DEV_STATE_ERROR
|
BUG_ON(dev->state != DEV_STATE_ERROR
|
||||||
&& dev->state != DEV_STATE_CAPTURING
|
&& dev->state != DEV_STATE_CAPTURING
|
||||||
&& dev->state != DEV_STATE_CAPTURE_DONE);
|
&& dev->state != DEV_STATE_CAPTURE_DONE);
|
||||||
@@ -505,7 +699,7 @@ API_EXPORTED int fp_async_capture_stop(struct fp_dev *dev,
|
|||||||
|
|
||||||
r = drv->capture_stop(dev);
|
r = drv->capture_stop(dev);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
fp_err("failed to stop verification");
|
fp_err("failed to stop capture");
|
||||||
dev->capture_stop_cb = NULL;
|
dev->capture_stop_cb = NULL;
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
39
libfprint/fpi-async.h
Normal file
39
libfprint/fpi-async.h
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __FPI_ASYNC_H__
|
||||||
|
#define __FPI_ASYNC_H__
|
||||||
|
|
||||||
|
#include "fpi-dev.h"
|
||||||
|
#include "fpi-data.h"
|
||||||
|
|
||||||
|
void fpi_drvcb_open_complete(struct fp_dev *dev, int status);
|
||||||
|
void fpi_drvcb_close_complete(struct fp_dev *dev);
|
||||||
|
|
||||||
|
void fpi_drvcb_enroll_started(struct fp_dev *dev, int status);
|
||||||
|
void fpi_drvcb_enroll_stage_completed(struct fp_dev *dev, int result,
|
||||||
|
struct fp_print_data *data, struct fp_img *img);
|
||||||
|
void fpi_drvcb_enroll_stopped(struct fp_dev *dev);
|
||||||
|
|
||||||
|
void fpi_drvcb_verify_started(struct fp_dev *dev, int status);
|
||||||
|
void fpi_drvcb_report_verify_result(struct fp_dev *dev, int result,
|
||||||
|
struct fp_img *img);
|
||||||
|
void fpi_drvcb_verify_stopped(struct fp_dev *dev);
|
||||||
|
|
||||||
|
#endif
|
||||||
835
libfprint/fpi-core.c
Normal file
835
libfprint/fpi-core.c
Normal file
@@ -0,0 +1,835 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
* @short_description: Device discovery functions
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* @short_description: Driver operation functions
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* @short_description: Device operation functions
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SECTION:fpi-core
|
||||||
|
* @title: Driver structures
|
||||||
|
* @short_description: Driver structures
|
||||||
|
*
|
||||||
|
* Driver structures need to be defined inside each driver in
|
||||||
|
* order for the core library to know what function to call, and the capabilities
|
||||||
|
* of the driver and the devices it supports.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SECTION:fpi-core-img
|
||||||
|
* @title: Image driver structures
|
||||||
|
* @short_description: Image driver structures
|
||||||
|
*
|
||||||
|
* Image driver structures need to be defined inside each image driver in
|
||||||
|
* order for the core library to know what function to call, and the capabilities
|
||||||
|
* of the driver and the devices it supports. Its structure is based off the
|
||||||
|
* #fp_driver struct.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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. Note that %NULL
|
||||||
|
* is only returned on error. When there are no supported readers available,
|
||||||
|
* an empty list is returned instead.
|
||||||
|
*
|
||||||
|
* Returns: a nul-terminated list of discovered devices or %NULL on error.
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
g_return_val_if_fail (registered_drivers != NULL, 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)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail(dev, NULL);
|
||||||
|
|
||||||
|
return dev->drv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fp_dscv_dev_get_driver_id:
|
||||||
|
* @dev: a discovered fingerprint device
|
||||||
|
*
|
||||||
|
* Returns a unique driver identifier for the underlying driver
|
||||||
|
* for that device.
|
||||||
|
*
|
||||||
|
* Returns: the ID for #dev
|
||||||
|
*/
|
||||||
|
API_EXPORTED uint16_t fp_dscv_dev_get_driver_id(struct fp_dscv_dev *dev)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail(dev, 0);
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail(dev, 0);
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail(dev, 0);
|
||||||
|
g_return_val_if_fail(print, 0);
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail(dev, 0);
|
||||||
|
g_return_val_if_fail(print, 0);
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
g_return_val_if_fail(devs, NULL);
|
||||||
|
g_return_val_if_fail(print, NULL);
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
g_return_val_if_fail(devs, NULL);
|
||||||
|
g_return_val_if_fail(print, NULL);
|
||||||
|
|
||||||
|
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 struct #fp_dev 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)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail(dev, NULL);
|
||||||
|
|
||||||
|
return dev->drv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fp_dev_get_nr_enroll_stages:
|
||||||
|
* @dev: the struct #fp_dev 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)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail(dev, 0);
|
||||||
|
|
||||||
|
return dev->nr_enroll_stages;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fp_dev_get_devtype:
|
||||||
|
* @dev: the struct #fp_dev 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)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail(dev, 0);
|
||||||
|
|
||||||
|
return dev->devtype;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fp_dev_supports_print_data:
|
||||||
|
* @dev: the struct #fp_dev 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)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail(dev, 0);
|
||||||
|
g_return_val_if_fail(data, 0);
|
||||||
|
|
||||||
|
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 struct #fp_dev 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)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail(dev, 0);
|
||||||
|
g_return_val_if_fail(print, 0);
|
||||||
|
|
||||||
|
return fpi_print_data_compatible(dev->drv->id, dev->devtype,
|
||||||
|
0, print->driver_id, print->devtype, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail(drv, NULL);
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail(drv, NULL);
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail(drv, 0);
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail(drv, FP_SCAN_TYPE_PRESS);
|
||||||
|
|
||||||
|
return drv->scan_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fp_driver_supports_imaging:
|
||||||
|
* @drv: the driver
|
||||||
|
*
|
||||||
|
* Determines if a driver has imaging capabilities. If a driver has imaging
|
||||||
|
* capabilities you are able to perform imaging operations such as retrieving
|
||||||
|
* scan images using fp_dev_img_capture(). However, not all drivers support
|
||||||
|
* 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_driver_supports_imaging(struct fp_driver *drv)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail(drv, 0);
|
||||||
|
|
||||||
|
return drv->capture_start != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fp_dev_supports_imaging:
|
||||||
|
* @dev: the struct #fp_dev 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)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail(dev, 0);
|
||||||
|
|
||||||
|
return dev->drv->capture_start != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fp_dev_supports_identification:
|
||||||
|
* @dev: the struct #fp_dev 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)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail(dev, 0);
|
||||||
|
|
||||||
|
return dev->drv->identify_start != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fp_dev_get_img_width:
|
||||||
|
* @dev: the struct #fp_dev 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)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail(dev, -1);
|
||||||
|
|
||||||
|
if (!dev->img_dev) {
|
||||||
|
fp_dbg("get image width for non-imaging device");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fpi_imgdev_get_img_width(dev->img_dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fp_dev_get_img_height:
|
||||||
|
* @dev: the struct #fp_dev 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)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail(dev, -1);
|
||||||
|
|
||||||
|
if (!dev->img_dev) {
|
||||||
|
fp_dbg("get image height for non-imaging device");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fpi_imgdev_get_img_height(dev->img_dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
|
|
||||||
118
libfprint/fpi-core.h
Normal file
118
libfprint/fpi-core.h
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __FPI_CORE_H__
|
||||||
|
#define __FPI_CORE_H__
|
||||||
|
|
||||||
|
#include <fprint.h>
|
||||||
|
#include "fpi-dev-img.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* usb_id:
|
||||||
|
* @vendor: the USB vendor ID
|
||||||
|
* @product: the USB product ID
|
||||||
|
* @driver_data: data to differentiate devices of different
|
||||||
|
* vendor and product IDs.
|
||||||
|
*
|
||||||
|
* The struct #usb_id is used to declare devices supported by a
|
||||||
|
* particular driver. The @driver_data information is used to
|
||||||
|
* differentiate different models of devices which only need
|
||||||
|
* small changes compared to the default driver behaviour to function.
|
||||||
|
*
|
||||||
|
* For example, a device might have a different initialisation from
|
||||||
|
* the stock device, so the driver could do:
|
||||||
|
*
|
||||||
|
* |[<!-- language="C" -->
|
||||||
|
* if (driver_data == MY_DIFFERENT_DEVICE_QUIRK) {
|
||||||
|
* ...
|
||||||
|
* } else {
|
||||||
|
* ...
|
||||||
|
* }
|
||||||
|
* ]|
|
||||||
|
*
|
||||||
|
* The default value is zero, so the @driver_data needs to be a
|
||||||
|
* non-zero to be useful.
|
||||||
|
*/
|
||||||
|
struct usb_id {
|
||||||
|
uint16_t vendor;
|
||||||
|
uint16_t product;
|
||||||
|
unsigned long driver_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fp_driver_type:
|
||||||
|
* @DRIVER_PRIMITIVE: primitive, non-imaging, driver
|
||||||
|
* @DRIVER_IMAGING: imaging driver
|
||||||
|
*
|
||||||
|
* The type of device the driver supports.
|
||||||
|
*/
|
||||||
|
enum fp_driver_type {
|
||||||
|
DRIVER_PRIMITIVE = 0,
|
||||||
|
DRIVER_IMAGING = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fp_driver {
|
||||||
|
const uint16_t id;
|
||||||
|
const char *name;
|
||||||
|
const char *full_name;
|
||||||
|
const struct usb_id * const id_table;
|
||||||
|
enum fp_driver_type type;
|
||||||
|
enum fp_scan_type scan_type;
|
||||||
|
|
||||||
|
/* Device operations */
|
||||||
|
int (*discover)(struct libusb_device_descriptor *dsc, uint32_t *devtype);
|
||||||
|
int (*open)(struct fp_dev *dev, unsigned long driver_data);
|
||||||
|
void (*close)(struct fp_dev *dev);
|
||||||
|
int (*enroll_start)(struct fp_dev *dev);
|
||||||
|
int (*enroll_stop)(struct fp_dev *dev);
|
||||||
|
int (*verify_start)(struct fp_dev *dev);
|
||||||
|
int (*verify_stop)(struct fp_dev *dev, gboolean iterating);
|
||||||
|
int (*identify_start)(struct fp_dev *dev);
|
||||||
|
int (*identify_stop)(struct fp_dev *dev, gboolean iterating);
|
||||||
|
int (*capture_start)(struct fp_dev *dev);
|
||||||
|
int (*capture_stop)(struct fp_dev *dev);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FpiImgDriverFlags:
|
||||||
|
* @FP_IMGDRV_SUPPORTS_UNCONDITIONAL_CAPTURE: Whether the driver supports
|
||||||
|
* unconditional image capture. No driver currently does.
|
||||||
|
*
|
||||||
|
* Flags used in the #fp_img_driver to advertise the capabilities of drivers.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
FP_IMGDRV_SUPPORTS_UNCONDITIONAL_CAPTURE = 1 << 0
|
||||||
|
} FpiImgDriverFlags;
|
||||||
|
|
||||||
|
struct fp_img_driver {
|
||||||
|
struct fp_driver driver;
|
||||||
|
FpiImgDriverFlags flags;
|
||||||
|
int img_width;
|
||||||
|
int img_height;
|
||||||
|
int bz3_threshold;
|
||||||
|
|
||||||
|
/* Device operations */
|
||||||
|
int (*open)(struct fp_img_dev *dev, unsigned long driver_data);
|
||||||
|
void (*close)(struct fp_img_dev *dev);
|
||||||
|
int (*activate)(struct fp_img_dev *dev);
|
||||||
|
int (*change_state)(struct fp_img_dev *dev, enum fp_imgdev_state state);
|
||||||
|
void (*deactivate)(struct fp_img_dev *dev);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -32,19 +32,49 @@
|
|||||||
|
|
||||||
#define DIR_PERMS 0700
|
#define DIR_PERMS 0700
|
||||||
|
|
||||||
/** @defgroup print_data Stored prints
|
struct fpi_print_data_fp2 {
|
||||||
* Stored prints are represented by a structure named <tt>fp_print_data</tt>.
|
char prefix[3];
|
||||||
|
uint16_t driver_id;
|
||||||
|
uint32_t devtype;
|
||||||
|
unsigned char data_type;
|
||||||
|
unsigned char data[0];
|
||||||
|
} __attribute__((__packed__));
|
||||||
|
|
||||||
|
struct fpi_print_data_item_fp2 {
|
||||||
|
uint32_t length;
|
||||||
|
unsigned char data[0];
|
||||||
|
} __attribute__((__packed__));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SECTION: print_data
|
||||||
|
* @title: Stored prints
|
||||||
|
* @short_description: Stored prints functions
|
||||||
|
*
|
||||||
|
* Stored prints are represented by a structure named #fp_print_data.
|
||||||
* Stored prints are originally obtained from an enrollment function such as
|
* Stored prints are originally obtained from an enrollment function such as
|
||||||
* fp_enroll_finger().
|
* fp_enroll_finger().
|
||||||
*
|
*
|
||||||
* This page documents the various operations you can do with a stored print.
|
* This page documents the various operations you can do with a stored print.
|
||||||
* Note that by default, "stored prints" are not actually stored anywhere
|
* Note that by default, "stored prints" are not actually stored anywhere
|
||||||
* except in RAM. For the simple scenarios, libfprint provides a simple API
|
* except in RAM. Storage needs to be handled by the API user by using the
|
||||||
* for you to save and load the stored prints referring to a single user in
|
* fp_print_data_get_data() and fp_print_data_from_data(). This API allows
|
||||||
* their home directory. For more advanced users, libfprint provides APIs for
|
* to convert print data into byte strings, and to reconstruct stored prints
|
||||||
* 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
|
* from such data at a later point. You are welcome to store these byte strings
|
||||||
* in any fashion that suits you.
|
* in any fashion that suits you.
|
||||||
|
*
|
||||||
|
* The provided API to store data on disk is deprecated and should not be
|
||||||
|
* used anymore. This API stored the prints in the current user's home
|
||||||
|
* directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SECTION: fpi-data
|
||||||
|
* @title: Stored prints creation
|
||||||
|
* @short_description: Stored prints creation functions
|
||||||
|
*
|
||||||
|
* Stored print can be loaded and created by certain drivers which do their own
|
||||||
|
* print matching in hardware. Most drivers will not be using those functions.
|
||||||
|
* See #fp_print_data for the public API counterpart.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static char *base_store = NULL;
|
static char *base_store = NULL;
|
||||||
@@ -73,7 +103,6 @@ void fpi_data_exit(void)
|
|||||||
((finger) >= LEFT_THUMB && (finger) <= RIGHT_LITTLE)
|
((finger) >= LEFT_THUMB && (finger) <= RIGHT_LITTLE)
|
||||||
|
|
||||||
/* for debug messages only */
|
/* for debug messages only */
|
||||||
#ifdef ENABLE_DEBUG_LOGGING
|
|
||||||
static const char *finger_num_to_str(enum fp_finger finger)
|
static const char *finger_num_to_str(enum fp_finger finger)
|
||||||
{
|
{
|
||||||
const char *names[] = {
|
const char *names[] = {
|
||||||
@@ -92,7 +121,6 @@ static const char *finger_num_to_str(enum fp_finger finger)
|
|||||||
return "UNKNOWN";
|
return "UNKNOWN";
|
||||||
return names[finger];
|
return names[finger];
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
static struct fp_print_data *print_data_new(uint16_t driver_id,
|
static struct fp_print_data *print_data_new(uint16_t driver_id,
|
||||||
uint32_t devtype, enum fp_print_data_type type)
|
uint32_t devtype, enum fp_print_data_type type)
|
||||||
@@ -105,14 +133,14 @@ static struct fp_print_data *print_data_new(uint16_t driver_id,
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void fpi_print_data_item_free(struct fp_print_data_item *item)
|
static void fpi_print_data_item_free(struct fp_print_data_item *item)
|
||||||
{
|
{
|
||||||
g_free(item);
|
g_free(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct fp_print_data_item *fpi_print_data_item_new(size_t length)
|
struct fp_print_data_item *fpi_print_data_item_new(size_t length)
|
||||||
{
|
{
|
||||||
struct fp_print_data_item *item = g_malloc(sizeof(*item) + length);
|
struct fp_print_data_item *item = g_malloc0(sizeof(*item) + length);
|
||||||
item->length = length;
|
item->length = length;
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
@@ -124,14 +152,30 @@ struct fp_print_data *fpi_print_data_new(struct fp_dev *dev)
|
|||||||
fpi_driver_get_data_type(dev->drv));
|
fpi_driver_get_data_type(dev->drv));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \ingroup print_data
|
struct fp_print_data_item *
|
||||||
|
fpi_print_data_get_item(struct fp_print_data *data)
|
||||||
|
{
|
||||||
|
return data->prints->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
fpi_print_data_add_item(struct fp_print_data *data,
|
||||||
|
struct fp_print_data_item *item)
|
||||||
|
{
|
||||||
|
data->prints = g_slist_prepend(data->prints, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
* 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
|
* 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().
|
* it back at some later time using fp_print_data_from_data().
|
||||||
* \param data the stored print
|
*
|
||||||
* \param ret output location for the data buffer. Must be freed with free()
|
* Returns: the size of the freshly allocated buffer, or 0 on error.
|
||||||
* after use.
|
|
||||||
* \returns the size of the freshly allocated buffer, or 0 on error.
|
|
||||||
*/
|
*/
|
||||||
API_EXPORTED size_t fp_print_data_get_data(struct fp_print_data *data,
|
API_EXPORTED size_t fp_print_data_get_data(struct fp_print_data *data,
|
||||||
unsigned char **ret)
|
unsigned char **ret)
|
||||||
@@ -143,7 +187,7 @@ API_EXPORTED size_t fp_print_data_get_data(struct fp_print_data *data,
|
|||||||
GSList *list_item;
|
GSList *list_item;
|
||||||
unsigned char *buf;
|
unsigned char *buf;
|
||||||
|
|
||||||
fp_dbg("");
|
G_DEBUG_HERE();
|
||||||
|
|
||||||
list_item = data->prints;
|
list_item = data->prints;
|
||||||
while (list_item) {
|
while (list_item) {
|
||||||
@@ -170,7 +214,7 @@ API_EXPORTED size_t fp_print_data_get_data(struct fp_print_data *data,
|
|||||||
item = list_item->data;
|
item = list_item->data;
|
||||||
out_item = (struct fpi_print_data_item_fp2 *)buf;
|
out_item = (struct fpi_print_data_item_fp2 *)buf;
|
||||||
out_item->length = GUINT32_TO_LE(item->length);
|
out_item->length = GUINT32_TO_LE(item->length);
|
||||||
/* FIXME: fp_print_data_item->data content is not endianess agnostic */
|
/* FIXME: fp_print_data_item->data content is not endianness agnostic */
|
||||||
memcpy(out_item->data, item->data, item->length);
|
memcpy(out_item->data, item->data, item->length);
|
||||||
buf += sizeof(*out_item);
|
buf += sizeof(*out_item);
|
||||||
buf += item->length;
|
buf += item->length;
|
||||||
@@ -192,7 +236,7 @@ static struct fp_print_data *fpi_print_data_from_fp1_data(unsigned char *buf,
|
|||||||
data = print_data_new(GUINT16_FROM_LE(raw->driver_id),
|
data = print_data_new(GUINT16_FROM_LE(raw->driver_id),
|
||||||
GUINT32_FROM_LE(raw->devtype), raw->data_type);
|
GUINT32_FROM_LE(raw->devtype), raw->data_type);
|
||||||
item = fpi_print_data_item_new(print_data_len);
|
item = fpi_print_data_item_new(print_data_len);
|
||||||
/* FIXME: fp_print_data->data content is not endianess agnostic */
|
/* FIXME: fp_print_data->data content is not endianness agnostic */
|
||||||
memcpy(item->data, raw->data, print_data_len);
|
memcpy(item->data, raw->data, print_data_len);
|
||||||
data->prints = g_slist_prepend(data->prints, item);
|
data->prints = g_slist_prepend(data->prints, item);
|
||||||
|
|
||||||
@@ -220,7 +264,7 @@ static struct fp_print_data *fpi_print_data_from_fp2_data(unsigned char *buf,
|
|||||||
|
|
||||||
raw_item = (struct fpi_print_data_item_fp2 *)raw_buf;
|
raw_item = (struct fpi_print_data_item_fp2 *)raw_buf;
|
||||||
item_len = GUINT32_FROM_LE(raw_item->length);
|
item_len = GUINT32_FROM_LE(raw_item->length);
|
||||||
fp_dbg("item len %d, total_data_len %d", item_len, total_data_len);
|
fp_dbg("item len %d, total_data_len %d", (int) item_len, (int) total_data_len);
|
||||||
if (total_data_len < item_len) {
|
if (total_data_len < item_len) {
|
||||||
fp_err("corrupted fingerprint data");
|
fp_err("corrupted fingerprint data");
|
||||||
break;
|
break;
|
||||||
@@ -228,7 +272,7 @@ static struct fp_print_data *fpi_print_data_from_fp2_data(unsigned char *buf,
|
|||||||
total_data_len -= item_len;
|
total_data_len -= item_len;
|
||||||
|
|
||||||
item = fpi_print_data_item_new(item_len);
|
item = fpi_print_data_item_new(item_len);
|
||||||
/* FIXME: fp_print_data->data content is not endianess agnostic */
|
/* FIXME: fp_print_data->data content is not endianness agnostic */
|
||||||
memcpy(item->data, raw_item->data, item_len);
|
memcpy(item->data, raw_item->data, item_len);
|
||||||
data->prints = g_slist_prepend(data->prints, item);
|
data->prints = g_slist_prepend(data->prints, item);
|
||||||
|
|
||||||
@@ -245,13 +289,16 @@ static struct fp_print_data *fpi_print_data_from_fp2_data(unsigned char *buf,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \ingroup print_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
|
* 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
|
* be the untouched contents of a buffer previously supplied to you by the
|
||||||
* fp_print_data_get_data() function.
|
* fp_print_data_get_data() function.
|
||||||
* \param buf the data buffer
|
*
|
||||||
* \param buflen the length of the buffer
|
* Returns: the stored print represented by the data, or %NULL on error. Must
|
||||||
* \returns the stored print represented by the data, or NULL on error. Must
|
|
||||||
* be freed with fp_print_data_free() after use.
|
* be freed with fp_print_data_free() after use.
|
||||||
*/
|
*/
|
||||||
API_EXPORTED struct fp_print_data *fp_print_data_from_data(unsigned char *buf,
|
API_EXPORTED struct fp_print_data *fp_print_data_from_data(unsigned char *buf,
|
||||||
@@ -305,7 +352,11 @@ 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);
|
return __get_path_to_print(dev->drv->id, dev->devtype, finger);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \ingroup print_data
|
/**
|
||||||
|
* 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
|
* 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
|
* 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
|
* per-device-type limit. For example, you can store the users right index
|
||||||
@@ -316,9 +367,12 @@ static char *get_path_to_print(struct fp_dev *dev, enum fp_finger finger)
|
|||||||
* This function will unconditionally overwrite a fingerprint previously
|
* This function will unconditionally overwrite a fingerprint previously
|
||||||
* saved for the same finger and device type. The print is saved in a hidden
|
* saved for the same finger and device type. The print is saved in a hidden
|
||||||
* directory beneath the current user's home directory.
|
* directory beneath the current user's home directory.
|
||||||
* \param data the stored print to save to disk
|
*
|
||||||
* \param finger the finger that this print corresponds to
|
* Returns: 0 on success, non-zero on error.
|
||||||
* \returns 0 on success, non-zero on error.
|
*
|
||||||
|
* Deprecated: Data storage should be handled outside of libfprint.
|
||||||
|
* See <link linkend="libfprint-Stored-prints.description">stored prints description</link>
|
||||||
|
* for more information.
|
||||||
*/
|
*/
|
||||||
API_EXPORTED int fp_print_data_save(struct fp_print_data *data,
|
API_EXPORTED int fp_print_data_save(struct fp_print_data *data,
|
||||||
enum fp_finger finger)
|
enum fp_finger finger)
|
||||||
@@ -344,6 +398,7 @@ API_EXPORTED int fp_print_data_save(struct fp_print_data *data,
|
|||||||
r = g_mkdir_with_parents(dirpath, DIR_PERMS);
|
r = g_mkdir_with_parents(dirpath, DIR_PERMS);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
fp_err("couldn't create storage directory");
|
fp_err("couldn't create storage directory");
|
||||||
|
free(buf);
|
||||||
g_free(path);
|
g_free(path);
|
||||||
g_free(dirpath);
|
g_free(dirpath);
|
||||||
return r;
|
return r;
|
||||||
@@ -415,7 +470,13 @@ static int load_from_file(char *path, struct fp_print_data **data)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \ingroup print_data
|
/**
|
||||||
|
* 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
|
* Loads a previously stored print from disk. The print must have been saved
|
||||||
* earlier using the fp_print_data_save() function.
|
* earlier using the fp_print_data_save() function.
|
||||||
*
|
*
|
||||||
@@ -423,17 +484,17 @@ static int load_from_file(char *path, struct fp_print_data **data)
|
|||||||
* be found. Other error codes (both positive and negative) are possible for
|
* be found. Other error codes (both positive and negative) are possible for
|
||||||
* obscure error conditions (e.g. corruption).
|
* obscure error conditions (e.g. corruption).
|
||||||
*
|
*
|
||||||
* \param dev the device you are loading the print for
|
* Returns: 0 on success, non-zero on error
|
||||||
* \param finger the finger of the file you are loading
|
*
|
||||||
* \param data output location to put the corresponding stored print. Must be
|
* Deprecated: Data storage should be handled outside of libfprint.
|
||||||
* freed with fp_print_data_free() after use.
|
* See <link linkend="libfprint-Stored-prints.description">stored prints description</link>
|
||||||
* \returns 0 on success, non-zero on error
|
* for more information.
|
||||||
*/
|
*/
|
||||||
API_EXPORTED int fp_print_data_load(struct fp_dev *dev,
|
API_EXPORTED int fp_print_data_load(struct fp_dev *dev,
|
||||||
enum fp_finger finger, struct fp_print_data **data)
|
enum fp_finger finger, struct fp_print_data **data)
|
||||||
{
|
{
|
||||||
gchar *path;
|
gchar *path;
|
||||||
struct fp_print_data *fdata;
|
struct fp_print_data *fdata = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (!base_store)
|
if (!base_store)
|
||||||
@@ -455,11 +516,18 @@ API_EXPORTED int fp_print_data_load(struct fp_dev *dev,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \ingroup print_data
|
/**
|
||||||
|
* 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().
|
* Removes a stored print from disk previously saved with fp_print_data_save().
|
||||||
* \param dev the device that the print belongs to
|
*
|
||||||
* \param finger the finger of the file you are deleting
|
* Returns: 0 on success, negative on error
|
||||||
* \returns 0 on success, negative on error
|
*
|
||||||
|
* Deprecated: Data storage should be handled outside of libfprint.
|
||||||
|
* See <link linkend="libfprint-Stored-prints.description">stored prints description</link>
|
||||||
|
* for more information.
|
||||||
*/
|
*/
|
||||||
API_EXPORTED int fp_print_data_delete(struct fp_dev *dev,
|
API_EXPORTED int fp_print_data_delete(struct fp_dev *dev,
|
||||||
enum fp_finger finger)
|
enum fp_finger finger)
|
||||||
@@ -477,18 +545,22 @@ API_EXPORTED int fp_print_data_delete(struct fp_dev *dev,
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \ingroup print_data
|
/**
|
||||||
* Attempts to load a stored print based on a \ref dscv_print
|
* fp_print_data_from_dscv_print:
|
||||||
* "discovered print" record.
|
* @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
|
* 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
|
* discovered print could not be found. Other error codes (both positive and
|
||||||
* negative) are possible for obscure error conditions (e.g. corruption).
|
* negative) are possible for obscure error conditions (e.g. corruption).
|
||||||
*
|
*
|
||||||
* \param print the discovered print
|
* Returns: 0 on success, non-zero on error.
|
||||||
* \param data output location to point to the corresponding stored print. Must
|
*
|
||||||
* be freed with fp_print_data_free() after use.
|
* Deprecated: Do not use.
|
||||||
* \returns 0 on success, non-zero on error.
|
|
||||||
*/
|
*/
|
||||||
API_EXPORTED int fp_print_data_from_dscv_print(struct fp_dscv_print *print,
|
API_EXPORTED int fp_print_data_from_dscv_print(struct fp_dscv_print *print,
|
||||||
struct fp_print_data **data)
|
struct fp_print_data **data)
|
||||||
@@ -496,9 +568,11 @@ API_EXPORTED int fp_print_data_from_dscv_print(struct fp_dscv_print *print,
|
|||||||
return load_from_file(print->path, data);
|
return load_from_file(print->path, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \ingroup print_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.
|
* Frees a stored print. Must be called when you are finished using the print.
|
||||||
* \param data the stored print to destroy. If NULL, function simply returns.
|
|
||||||
*/
|
*/
|
||||||
API_EXPORTED void fp_print_data_free(struct fp_print_data *data)
|
API_EXPORTED void fp_print_data_free(struct fp_print_data *data)
|
||||||
{
|
{
|
||||||
@@ -507,31 +581,41 @@ API_EXPORTED void fp_print_data_free(struct fp_print_data *data)
|
|||||||
g_free(data);
|
g_free(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \ingroup print_data
|
/**
|
||||||
* Gets the \ref driver_id "driver ID" for a stored print. The driver ID
|
* 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
|
* indicates which driver the print originally came from. The print is
|
||||||
* only usable with a device controlled by that driver.
|
* only usable with a device controlled by that driver.
|
||||||
* \param data the stored print
|
*
|
||||||
* \returns the driver ID of the driver compatible with the print
|
* 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)
|
API_EXPORTED uint16_t fp_print_data_get_driver_id(struct fp_print_data *data)
|
||||||
{
|
{
|
||||||
return data->driver_id;
|
return data->driver_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \ingroup print_data
|
/**
|
||||||
* Gets the \ref devtype "devtype" for a stored print. The devtype represents
|
* 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.
|
* which type of device under the parent driver is compatible with the print.
|
||||||
* \param data the stored print
|
*
|
||||||
* \returns the devtype of the device range compatible with the print
|
* 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)
|
API_EXPORTED uint32_t fp_print_data_get_devtype(struct fp_print_data *data)
|
||||||
{
|
{
|
||||||
return data->devtype;
|
return data->devtype;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @defgroup dscv_print Print discovery
|
/**
|
||||||
* The \ref print_data "stored print" documentation detailed a simple API
|
* SECTION:dscv_print
|
||||||
|
* @title: Print discovery (deprecated)
|
||||||
|
* @short_description: Print discovery functions
|
||||||
|
*
|
||||||
|
* The [stored print](libfprint-Stored-prints.html) documentation detailed a simple API
|
||||||
* for storing per-device prints for a single user, namely
|
* for storing per-device prints for a single user, namely
|
||||||
* fp_print_data_save(). It also detailed a load function,
|
* fp_print_data_save(). It also detailed a load function,
|
||||||
* fp_print_data_load(), but usage of this function is limited to scenarios
|
* fp_print_data_load(), but usage of this function is limited to scenarios
|
||||||
@@ -542,7 +626,7 @@ API_EXPORTED uint32_t fp_print_data_get_devtype(struct fp_print_data *data)
|
|||||||
* previously saved prints, potentially even before device discovery. These
|
* previously saved prints, potentially even before device discovery. These
|
||||||
* functions are designed to offer this functionality to you.
|
* functions are designed to offer this functionality to you.
|
||||||
*
|
*
|
||||||
* Discovered prints are stored in a <tt>dscv_print</tt> structure, and you
|
* Discovered prints are stored in a #fp_dscv_print structure, and you
|
||||||
* can use functions documented below to access some information about these
|
* can use functions documented below to access some information about these
|
||||||
* prints. You can determine if a discovered print appears to be compatible
|
* 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
|
* with a device using functions such as fp_dscv_dev_supports_dscv_print() and
|
||||||
@@ -560,6 +644,10 @@ API_EXPORTED uint32_t fp_print_data_get_devtype(struct fp_print_data *data)
|
|||||||
* circumstances it may turn out that the print is corrupt or not for the
|
* 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
|
* 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.
|
* 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,
|
static GSList *scan_dev_store_dir(char *devpath, uint16_t driver_id,
|
||||||
@@ -643,11 +731,16 @@ static GSList *scan_driver_store_dir(char *drvpath, uint16_t driver_id,
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \ingroup dscv_print
|
/**
|
||||||
|
* fp_discover_prints:
|
||||||
|
*
|
||||||
* Scans the users home directory and returns a list of prints that were
|
* Scans the users home directory and returns a list of prints that were
|
||||||
* previously saved using fp_print_data_save().
|
* previously saved using fp_print_data_save().
|
||||||
* \returns a NULL-terminated list of discovered prints, must be freed with
|
*
|
||||||
|
* Returns: a %NULL-terminated list of discovered prints, must be freed with
|
||||||
* fp_dscv_prints_free() after use.
|
* fp_dscv_prints_free() after use.
|
||||||
|
*
|
||||||
|
* Deprecated: Do not use.
|
||||||
*/
|
*/
|
||||||
API_EXPORTED struct fp_dscv_print **fp_discover_prints(void)
|
API_EXPORTED struct fp_dscv_print **fp_discover_prints(void)
|
||||||
{
|
{
|
||||||
@@ -656,9 +749,7 @@ API_EXPORTED struct fp_dscv_print **fp_discover_prints(void)
|
|||||||
GError *err = NULL;
|
GError *err = NULL;
|
||||||
GSList *tmplist = NULL;
|
GSList *tmplist = NULL;
|
||||||
GSList *elem;
|
GSList *elem;
|
||||||
unsigned int tmplist_len;
|
GPtrArray *array;
|
||||||
struct fp_dscv_print **list;
|
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
if (!base_store)
|
if (!base_store)
|
||||||
storage_setup();
|
storage_setup();
|
||||||
@@ -693,23 +784,29 @@ API_EXPORTED struct fp_dscv_print **fp_discover_prints(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
g_dir_close(dir);
|
g_dir_close(dir);
|
||||||
tmplist_len = g_slist_length(tmplist);
|
|
||||||
list = g_malloc(sizeof(*list) * (tmplist_len + 1));
|
if (tmplist == NULL)
|
||||||
elem = tmplist;
|
return NULL;
|
||||||
for (i = 0; i < tmplist_len; i++, elem = g_slist_next(elem))
|
|
||||||
list[i] = elem->data;
|
array = g_ptr_array_new();
|
||||||
list[tmplist_len] = NULL; /* NULL-terminate */
|
for (elem = tmplist; elem != NULL; elem = elem->next)
|
||||||
|
g_ptr_array_add(array, elem->data);
|
||||||
|
g_ptr_array_add(array, NULL);
|
||||||
|
|
||||||
g_slist_free(tmplist);
|
g_slist_free(tmplist);
|
||||||
return list;
|
return (struct fp_dscv_print **) g_ptr_array_free(array, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \ingroup dscv_print
|
/**
|
||||||
|
* 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
|
* Frees a list of discovered prints. This function also frees the discovered
|
||||||
* prints themselves, so make sure you do not use any discovered prints
|
* prints themselves, so make sure you do not use any discovered prints
|
||||||
* after calling this function.
|
* after calling this function.
|
||||||
* \param prints the list of discovered prints. If NULL, function simply
|
*
|
||||||
* returns.
|
* Deprecated: Do not use.
|
||||||
*/
|
*/
|
||||||
API_EXPORTED void fp_dscv_prints_free(struct fp_dscv_print **prints)
|
API_EXPORTED void fp_dscv_prints_free(struct fp_dscv_print **prints)
|
||||||
{
|
{
|
||||||
@@ -727,47 +824,67 @@ API_EXPORTED void fp_dscv_prints_free(struct fp_dscv_print **prints)
|
|||||||
g_free(prints);
|
g_free(prints);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \ingroup dscv_print
|
/**
|
||||||
* Gets the \ref driver_id "driver ID" for a discovered print. The driver ID
|
* 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
|
* indicates which driver the print originally came from. The print is only
|
||||||
* usable with a device controlled by that driver.
|
* usable with a device controlled by that driver.
|
||||||
* \param print the discovered print
|
*
|
||||||
* \returns the driver ID of the driver compatible with the print
|
* 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)
|
API_EXPORTED uint16_t fp_dscv_print_get_driver_id(struct fp_dscv_print *print)
|
||||||
{
|
{
|
||||||
return print->driver_id;
|
return print->driver_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \ingroup dscv_print
|
/**
|
||||||
* Gets the \ref devtype "devtype" for a discovered print. The devtype
|
* 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
|
* represents which type of device under the parent driver is compatible
|
||||||
* with the print.
|
* with the print.
|
||||||
* \param print the discovered print
|
*
|
||||||
* \returns the devtype of the device range 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)
|
API_EXPORTED uint32_t fp_dscv_print_get_devtype(struct fp_dscv_print *print)
|
||||||
{
|
{
|
||||||
return print->devtype;
|
return print->devtype;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \ingroup dscv_print
|
/**
|
||||||
|
* fp_dscv_print_get_finger:
|
||||||
|
* @print: discovered print
|
||||||
|
*
|
||||||
* Gets the finger code for a discovered print.
|
* Gets the finger code for a discovered print.
|
||||||
* \param print discovered print
|
*
|
||||||
* \returns a finger code from #fp_finger
|
* 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)
|
API_EXPORTED enum fp_finger fp_dscv_print_get_finger(struct fp_dscv_print *print)
|
||||||
{
|
{
|
||||||
return print->finger;
|
return print->finger;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \ingroup dscv_print
|
/**
|
||||||
|
* fp_dscv_print_delete:
|
||||||
|
* @print: the discovered print to remove from disk
|
||||||
|
*
|
||||||
* Removes a discovered print from disk. After successful return of this
|
* Removes a discovered print from disk. After successful return of this
|
||||||
* function, functions such as fp_dscv_print_get_finger() will continue to
|
* function, functions such as fp_dscv_print_get_finger() will continue to
|
||||||
* operate as before, however calling fp_print_data_from_dscv_print() will
|
* operate as before, however calling fp_print_data_from_dscv_print() will
|
||||||
* fail for obvious reasons.
|
* fail for obvious reasons.
|
||||||
* \param print the discovered print to remove from disk
|
*
|
||||||
* \returns 0 on success, negative on error
|
* Returns: 0 on success, negative on error
|
||||||
|
*
|
||||||
|
* Deprecated: Do not use.
|
||||||
*/
|
*/
|
||||||
API_EXPORTED int fp_dscv_print_delete(struct fp_dscv_print *print)
|
API_EXPORTED int fp_dscv_print_delete(struct fp_dscv_print *print)
|
||||||
{
|
{
|
||||||
34
libfprint/fpi-data.h
Normal file
34
libfprint/fpi-data.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __FPI_DATA_H__
|
||||||
|
#define __FPI_DATA_H__
|
||||||
|
|
||||||
|
struct fp_print_data;
|
||||||
|
struct fp_print_data_item {
|
||||||
|
size_t length;
|
||||||
|
unsigned char data[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fp_print_data *fpi_print_data_new(struct fp_dev *dev);
|
||||||
|
struct fp_print_data_item *fpi_print_data_item_new(size_t length);
|
||||||
|
struct fp_print_data_item *fpi_print_data_get_item(struct fp_print_data *data);
|
||||||
|
void fpi_print_data_add_item(struct fp_print_data *data, struct fp_print_data_item *item);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -21,25 +21,93 @@
|
|||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
|
||||||
|
#include "fpi-dev-img.h"
|
||||||
|
#include "fpi-async.h"
|
||||||
#include "fp_internal.h"
|
#include "fp_internal.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SECTION:fpi-dev-img
|
||||||
|
* @title: Image device operations
|
||||||
|
* @short_description: Image device operation functions
|
||||||
|
*
|
||||||
|
* As drivers work through different operations, they need to report back
|
||||||
|
* to the core as to their internal state, so errors and successes can be
|
||||||
|
* reported back to front-ends.
|
||||||
|
*/
|
||||||
|
|
||||||
#define MIN_ACCEPTABLE_MINUTIAE 10
|
#define MIN_ACCEPTABLE_MINUTIAE 10
|
||||||
#define BOZORTH3_DEFAULT_THRESHOLD 40
|
#define BOZORTH3_DEFAULT_THRESHOLD 40
|
||||||
#define IMG_ENROLL_STAGES 5
|
#define IMG_ENROLL_STAGES 5
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_imgdev_get_action_state:
|
||||||
|
* @imgdev: a #fp_img_dev imaging fingerprint device
|
||||||
|
*
|
||||||
|
* Returns the state of an imaging device while enrolling a fingerprint.
|
||||||
|
*
|
||||||
|
* Returns: a enum #fp_imgdev_enroll_state
|
||||||
|
*/
|
||||||
|
enum fp_imgdev_enroll_state
|
||||||
|
fpi_imgdev_get_action_state(struct fp_img_dev *imgdev)
|
||||||
|
{
|
||||||
|
return imgdev->action_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_imgdev_get_action:
|
||||||
|
* @imgdev: a #fp_img_dev imaging fingerprint device
|
||||||
|
*
|
||||||
|
* Returns the current action being performed by an imaging device.
|
||||||
|
*
|
||||||
|
* Returns: a enum #fp_imgdev_action
|
||||||
|
*/
|
||||||
|
enum fp_imgdev_action
|
||||||
|
fpi_imgdev_get_action(struct fp_img_dev *imgdev)
|
||||||
|
{
|
||||||
|
return imgdev->action;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_imgdev_get_action_result:
|
||||||
|
* @imgdev: a #fp_img_dev imaging fingerprint device
|
||||||
|
*
|
||||||
|
* Returns an integer representing the result of an action. Which enum
|
||||||
|
* the result code is taken from depends on the current action being performed.
|
||||||
|
* See #fp_capture_result, #fp_enroll_result and #fp_verify_result.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
fpi_imgdev_get_action_result(struct fp_img_dev *imgdev)
|
||||||
|
{
|
||||||
|
return imgdev->action_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_imgdev_set_action_result:
|
||||||
|
* @imgdev: a #fp_img_dev imaging fingerprint device
|
||||||
|
* @action_result: an action result
|
||||||
|
*
|
||||||
|
* Drivers should use fpi_imgdev_image_captured() instead. This function
|
||||||
|
* should not be used, and will be removed soon.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
fpi_imgdev_set_action_result(struct fp_img_dev *imgdev,
|
||||||
|
int action_result)
|
||||||
|
{
|
||||||
|
imgdev->action_result = action_result;
|
||||||
|
}
|
||||||
|
|
||||||
static int img_dev_open(struct fp_dev *dev, unsigned long driver_data)
|
static int img_dev_open(struct fp_dev *dev, unsigned long driver_data)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *imgdev = g_malloc0(sizeof(*imgdev));
|
struct fp_img_dev *imgdev = g_malloc0(sizeof(*imgdev));
|
||||||
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(dev->drv);
|
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(dev->drv);
|
||||||
int r = 0;
|
int r = 0;
|
||||||
|
|
||||||
imgdev->dev = dev;
|
/* Set up back pointers */
|
||||||
imgdev->enroll_stage = 0;
|
dev->img_dev = imgdev;
|
||||||
dev->priv = imgdev;
|
imgdev->parent = dev;
|
||||||
dev->nr_enroll_stages = IMG_ENROLL_STAGES;
|
|
||||||
|
|
||||||
/* for consistency in driver code, allow udev access through imgdev */
|
imgdev->enroll_stage = 0;
|
||||||
imgdev->udev = dev->udev;
|
dev->nr_enroll_stages = IMG_ENROLL_STAGES;
|
||||||
|
|
||||||
if (imgdrv->open) {
|
if (imgdrv->open) {
|
||||||
r = imgdrv->open(imgdev, driver_data);
|
r = imgdrv->open(imgdev, driver_data);
|
||||||
@@ -55,32 +123,45 @@ err:
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_imgdev_open_complete:
|
||||||
|
* @imgdev: a #fp_img_dev imaging fingerprint device
|
||||||
|
* @status: an error code
|
||||||
|
*
|
||||||
|
* Function to call when the device has been opened, whether
|
||||||
|
* successfully of not.
|
||||||
|
*/
|
||||||
void fpi_imgdev_open_complete(struct fp_img_dev *imgdev, int status)
|
void fpi_imgdev_open_complete(struct fp_img_dev *imgdev, int status)
|
||||||
{
|
{
|
||||||
fpi_drvcb_open_complete(imgdev->dev, status);
|
fpi_drvcb_open_complete(FP_DEV(imgdev), status);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void img_dev_close(struct fp_dev *dev)
|
static void img_dev_close(struct fp_dev *dev)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *imgdev = dev->priv;
|
|
||||||
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(dev->drv);
|
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(dev->drv);
|
||||||
|
|
||||||
if (imgdrv->close)
|
if (imgdrv->close)
|
||||||
imgdrv->close(imgdev);
|
imgdrv->close(dev->img_dev);
|
||||||
else
|
else
|
||||||
fpi_drvcb_close_complete(dev);
|
fpi_drvcb_close_complete(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_imgdev_close_complete:
|
||||||
|
* @imgdev: a #fp_img_dev imaging fingerprint device
|
||||||
|
*
|
||||||
|
* Function to call when the device has been closed.
|
||||||
|
*/
|
||||||
void fpi_imgdev_close_complete(struct fp_img_dev *imgdev)
|
void fpi_imgdev_close_complete(struct fp_img_dev *imgdev)
|
||||||
{
|
{
|
||||||
fpi_drvcb_close_complete(imgdev->dev);
|
fpi_drvcb_close_complete(FP_DEV(imgdev));
|
||||||
g_free(imgdev);
|
g_free(imgdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dev_change_state(struct fp_img_dev *imgdev,
|
static int dev_change_state(struct fp_img_dev *imgdev,
|
||||||
enum fp_imgdev_state state)
|
enum fp_imgdev_state state)
|
||||||
{
|
{
|
||||||
struct fp_driver *drv = imgdev->dev->drv;
|
struct fp_driver *drv = FP_DEV(imgdev)->drv;
|
||||||
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv);
|
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv);
|
||||||
|
|
||||||
if (!imgdrv->change_state)
|
if (!imgdrv->change_state)
|
||||||
@@ -92,7 +173,7 @@ static int dev_change_state(struct fp_img_dev *imgdev,
|
|||||||
* image after freeing the old one. */
|
* image after freeing the old one. */
|
||||||
static int sanitize_image(struct fp_img_dev *imgdev, struct fp_img **_img)
|
static int sanitize_image(struct fp_img_dev *imgdev, struct fp_img **_img)
|
||||||
{
|
{
|
||||||
struct fp_driver *drv = imgdev->dev->drv;
|
struct fp_driver *drv = FP_DEV(imgdev)->drv;
|
||||||
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv);
|
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv);
|
||||||
struct fp_img *img = *_img;
|
struct fp_img *img = *_img;
|
||||||
|
|
||||||
@@ -118,6 +199,14 @@ static int sanitize_image(struct fp_img_dev *imgdev, struct fp_img **_img)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_imgdev_report_finger_status:
|
||||||
|
* @imgdev: a #fp_img_dev imaging fingerprint device
|
||||||
|
* @present: whether the finger is present on the sensor
|
||||||
|
*
|
||||||
|
* Reports from the driver whether the user's finger is on
|
||||||
|
* the sensor.
|
||||||
|
*/
|
||||||
void fpi_imgdev_report_finger_status(struct fp_img_dev *imgdev,
|
void fpi_imgdev_report_finger_status(struct fp_img_dev *imgdev,
|
||||||
gboolean present)
|
gboolean present)
|
||||||
{
|
{
|
||||||
@@ -150,7 +239,7 @@ void fpi_imgdev_report_finger_status(struct fp_img_dev *imgdev,
|
|||||||
if (r == FP_ENROLL_COMPLETE) {
|
if (r == FP_ENROLL_COMPLETE) {
|
||||||
imgdev->enroll_data = NULL;
|
imgdev->enroll_data = NULL;
|
||||||
}
|
}
|
||||||
fpi_drvcb_enroll_stage_completed(imgdev->dev, r,
|
fpi_drvcb_enroll_stage_completed(FP_DEV(imgdev), r,
|
||||||
r == FP_ENROLL_COMPLETE ? data : NULL,
|
r == FP_ENROLL_COMPLETE ? data : NULL,
|
||||||
img);
|
img);
|
||||||
/* the callback can cancel enrollment, so recheck current
|
/* the callback can cancel enrollment, so recheck current
|
||||||
@@ -159,20 +248,23 @@ void fpi_imgdev_report_finger_status(struct fp_img_dev *imgdev,
|
|||||||
r > 0 && r != FP_ENROLL_COMPLETE && r != FP_ENROLL_FAIL) {
|
r > 0 && r != FP_ENROLL_COMPLETE && r != FP_ENROLL_FAIL) {
|
||||||
imgdev->action_result = 0;
|
imgdev->action_result = 0;
|
||||||
imgdev->action_state = IMG_ACQUIRE_STATE_AWAIT_FINGER_ON;
|
imgdev->action_state = IMG_ACQUIRE_STATE_AWAIT_FINGER_ON;
|
||||||
dev_change_state(imgdev, IMG_ACQUIRE_STATE_AWAIT_FINGER_ON);
|
dev_change_state(imgdev, IMGDEV_STATE_AWAIT_FINGER_ON);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case IMG_ACTION_VERIFY:
|
case IMG_ACTION_VERIFY:
|
||||||
fpi_drvcb_report_verify_result(imgdev->dev, r, img);
|
fpi_drvcb_report_verify_result(FP_DEV(imgdev), r, img);
|
||||||
|
imgdev->action_result = 0;
|
||||||
fp_print_data_free(data);
|
fp_print_data_free(data);
|
||||||
break;
|
break;
|
||||||
case IMG_ACTION_IDENTIFY:
|
case IMG_ACTION_IDENTIFY:
|
||||||
fpi_drvcb_report_identify_result(imgdev->dev, r,
|
fpi_drvcb_report_identify_result(FP_DEV(imgdev), r,
|
||||||
imgdev->identify_match_offset, img);
|
imgdev->identify_match_offset, img);
|
||||||
|
imgdev->action_result = 0;
|
||||||
fp_print_data_free(data);
|
fp_print_data_free(data);
|
||||||
break;
|
break;
|
||||||
case IMG_ACTION_CAPTURE:
|
case IMG_ACTION_CAPTURE:
|
||||||
fpi_drvcb_report_capture_result(imgdev->dev, r, img);
|
fpi_drvcb_report_capture_result(FP_DEV(imgdev), r, img);
|
||||||
|
imgdev->action_result = 0;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fp_err("unhandled action %d", imgdev->action);
|
fp_err("unhandled action %d", imgdev->action);
|
||||||
@@ -182,14 +274,14 @@ void fpi_imgdev_report_finger_status(struct fp_img_dev *imgdev,
|
|||||||
|
|
||||||
static void verify_process_img(struct fp_img_dev *imgdev)
|
static void verify_process_img(struct fp_img_dev *imgdev)
|
||||||
{
|
{
|
||||||
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(imgdev->dev->drv);
|
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(FP_DEV(imgdev)->drv);
|
||||||
int match_score = imgdrv->bz3_threshold;
|
int match_score = imgdrv->bz3_threshold;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (match_score == 0)
|
if (match_score == 0)
|
||||||
match_score = BOZORTH3_DEFAULT_THRESHOLD;
|
match_score = BOZORTH3_DEFAULT_THRESHOLD;
|
||||||
|
|
||||||
r = fpi_img_compare_print_data(imgdev->dev->verify_data,
|
r = fpi_img_compare_print_data(FP_DEV(imgdev)->verify_data,
|
||||||
imgdev->acquire_data);
|
imgdev->acquire_data);
|
||||||
|
|
||||||
if (r >= match_score)
|
if (r >= match_score)
|
||||||
@@ -202,7 +294,7 @@ static void verify_process_img(struct fp_img_dev *imgdev)
|
|||||||
|
|
||||||
static void identify_process_img(struct fp_img_dev *imgdev)
|
static void identify_process_img(struct fp_img_dev *imgdev)
|
||||||
{
|
{
|
||||||
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(imgdev->dev->drv);
|
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(FP_DEV(imgdev)->drv);
|
||||||
int match_score = imgdrv->bz3_threshold;
|
int match_score = imgdrv->bz3_threshold;
|
||||||
size_t match_offset;
|
size_t match_offset;
|
||||||
int r;
|
int r;
|
||||||
@@ -211,17 +303,39 @@ static void identify_process_img(struct fp_img_dev *imgdev)
|
|||||||
match_score = BOZORTH3_DEFAULT_THRESHOLD;
|
match_score = BOZORTH3_DEFAULT_THRESHOLD;
|
||||||
|
|
||||||
r = fpi_img_compare_print_data_to_gallery(imgdev->acquire_data,
|
r = fpi_img_compare_print_data_to_gallery(imgdev->acquire_data,
|
||||||
imgdev->dev->identify_gallery, match_score, &match_offset);
|
FP_DEV(imgdev)->identify_gallery, match_score, &match_offset);
|
||||||
|
|
||||||
imgdev->action_result = r;
|
imgdev->action_result = r;
|
||||||
imgdev->identify_match_offset = match_offset;
|
imgdev->identify_match_offset = match_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_imgdev_abort_scan:
|
||||||
|
* @imgdev: a #fp_img_dev imaging fingerprint device
|
||||||
|
* @result: the scan result
|
||||||
|
*
|
||||||
|
* Aborts a scan after an error, and set the action result. See
|
||||||
|
* fpi_imgdev_get_action_result() for possible values.
|
||||||
|
*/
|
||||||
|
void fpi_imgdev_abort_scan(struct fp_img_dev *imgdev, int result)
|
||||||
|
{
|
||||||
|
imgdev->action_result = result;
|
||||||
|
imgdev->action_state = IMG_ACQUIRE_STATE_AWAIT_FINGER_OFF;
|
||||||
|
dev_change_state(imgdev, IMGDEV_STATE_AWAIT_FINGER_OFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_imgdev_image_captured:
|
||||||
|
* @imgdev: a #fp_img_dev imaging fingerprint device
|
||||||
|
* @img: an #fp_img image
|
||||||
|
*
|
||||||
|
* Report to the core that the driver captured this image from the sensor.
|
||||||
|
*/
|
||||||
void fpi_imgdev_image_captured(struct fp_img_dev *imgdev, struct fp_img *img)
|
void fpi_imgdev_image_captured(struct fp_img_dev *imgdev, struct fp_img *img)
|
||||||
{
|
{
|
||||||
struct fp_print_data *print;
|
struct fp_print_data *print = NULL;
|
||||||
int r;
|
int r;
|
||||||
fp_dbg("");
|
G_DEBUG_HERE();
|
||||||
|
|
||||||
if (imgdev->action_state != IMG_ACQUIRE_STATE_AWAIT_IMAGE) {
|
if (imgdev->action_state != IMG_ACQUIRE_STATE_AWAIT_IMAGE) {
|
||||||
fp_dbg("ignoring due to current state %d", imgdev->action_state);
|
fp_dbg("ignoring due to current state %d", imgdev->action_state);
|
||||||
@@ -262,7 +376,7 @@ void fpi_imgdev_image_captured(struct fp_img_dev *imgdev, struct fp_img *img)
|
|||||||
switch (imgdev->action) {
|
switch (imgdev->action) {
|
||||||
case IMG_ACTION_ENROLL:
|
case IMG_ACTION_ENROLL:
|
||||||
if (!imgdev->enroll_data) {
|
if (!imgdev->enroll_data) {
|
||||||
imgdev->enroll_data = fpi_print_data_new(imgdev->dev);
|
imgdev->enroll_data = fpi_print_data_new(FP_DEV(imgdev));
|
||||||
}
|
}
|
||||||
BUG_ON(g_slist_length(print->prints) != 1);
|
BUG_ON(g_slist_length(print->prints) != 1);
|
||||||
/* Move print data from acquire data into enroll_data */
|
/* Move print data from acquire data into enroll_data */
|
||||||
@@ -273,7 +387,7 @@ void fpi_imgdev_image_captured(struct fp_img_dev *imgdev, struct fp_img *img)
|
|||||||
fp_print_data_free(imgdev->acquire_data);
|
fp_print_data_free(imgdev->acquire_data);
|
||||||
imgdev->acquire_data = NULL;
|
imgdev->acquire_data = NULL;
|
||||||
imgdev->enroll_stage++;
|
imgdev->enroll_stage++;
|
||||||
if (imgdev->enroll_stage == imgdev->dev->nr_enroll_stages)
|
if (imgdev->enroll_stage == FP_DEV(imgdev)->nr_enroll_stages)
|
||||||
imgdev->action_result = FP_ENROLL_COMPLETE;
|
imgdev->action_result = FP_ENROLL_COMPLETE;
|
||||||
else
|
else
|
||||||
imgdev->action_result = FP_ENROLL_PASS;
|
imgdev->action_result = FP_ENROLL_PASS;
|
||||||
@@ -297,22 +411,29 @@ next_state:
|
|||||||
dev_change_state(imgdev, IMGDEV_STATE_AWAIT_FINGER_OFF);
|
dev_change_state(imgdev, IMGDEV_STATE_AWAIT_FINGER_OFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_imgdev_session_error:
|
||||||
|
* @imgdev: a #fp_img_dev imaging fingerprint device
|
||||||
|
* @error: an error code
|
||||||
|
*
|
||||||
|
* Report an error that occurred in the driver.
|
||||||
|
*/
|
||||||
void fpi_imgdev_session_error(struct fp_img_dev *imgdev, int error)
|
void fpi_imgdev_session_error(struct fp_img_dev *imgdev, int error)
|
||||||
{
|
{
|
||||||
fp_dbg("error %d", error);
|
fp_dbg("error %d", error);
|
||||||
BUG_ON(error == 0);
|
BUG_ON(error == 0);
|
||||||
switch (imgdev->action) {
|
switch (imgdev->action) {
|
||||||
case IMG_ACTION_ENROLL:
|
case IMG_ACTION_ENROLL:
|
||||||
fpi_drvcb_enroll_stage_completed(imgdev->dev, error, NULL, NULL);
|
fpi_drvcb_enroll_stage_completed(FP_DEV(imgdev), error, NULL, NULL);
|
||||||
break;
|
break;
|
||||||
case IMG_ACTION_VERIFY:
|
case IMG_ACTION_VERIFY:
|
||||||
fpi_drvcb_report_verify_result(imgdev->dev, error, NULL);
|
fpi_drvcb_report_verify_result(FP_DEV(imgdev), error, NULL);
|
||||||
break;
|
break;
|
||||||
case IMG_ACTION_IDENTIFY:
|
case IMG_ACTION_IDENTIFY:
|
||||||
fpi_drvcb_report_identify_result(imgdev->dev, error, 0, NULL);
|
fpi_drvcb_report_identify_result(FP_DEV(imgdev), error, 0, NULL);
|
||||||
break;
|
break;
|
||||||
case IMG_ACTION_CAPTURE:
|
case IMG_ACTION_CAPTURE:
|
||||||
fpi_drvcb_report_capture_result(imgdev->dev, error, NULL);
|
fpi_drvcb_report_capture_result(FP_DEV(imgdev), error, NULL);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fp_err("unhandled action %d", imgdev->action);
|
fp_err("unhandled action %d", imgdev->action);
|
||||||
@@ -320,22 +441,30 @@ void fpi_imgdev_session_error(struct fp_img_dev *imgdev, int error)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_imgdev_activate_complete:
|
||||||
|
* @imgdev: a #fp_img_dev imaging fingerprint device
|
||||||
|
* @status: the activation result
|
||||||
|
*
|
||||||
|
* Marks an activation as complete, whether successful or not.
|
||||||
|
* See fpi_imgdev_get_action_result() for possible values.
|
||||||
|
*/
|
||||||
void fpi_imgdev_activate_complete(struct fp_img_dev *imgdev, int status)
|
void fpi_imgdev_activate_complete(struct fp_img_dev *imgdev, int status)
|
||||||
{
|
{
|
||||||
fp_dbg("status %d", status);
|
fp_dbg("status %d", status);
|
||||||
|
|
||||||
switch (imgdev->action) {
|
switch (imgdev->action) {
|
||||||
case IMG_ACTION_ENROLL:
|
case IMG_ACTION_ENROLL:
|
||||||
fpi_drvcb_enroll_started(imgdev->dev, status);
|
fpi_drvcb_enroll_started(FP_DEV(imgdev), status);
|
||||||
break;
|
break;
|
||||||
case IMG_ACTION_VERIFY:
|
case IMG_ACTION_VERIFY:
|
||||||
fpi_drvcb_verify_started(imgdev->dev, status);
|
fpi_drvcb_verify_started(FP_DEV(imgdev), status);
|
||||||
break;
|
break;
|
||||||
case IMG_ACTION_IDENTIFY:
|
case IMG_ACTION_IDENTIFY:
|
||||||
fpi_drvcb_identify_started(imgdev->dev, status);
|
fpi_drvcb_identify_started(FP_DEV(imgdev), status);
|
||||||
break;
|
break;
|
||||||
case IMG_ACTION_CAPTURE:
|
case IMG_ACTION_CAPTURE:
|
||||||
fpi_drvcb_capture_started(imgdev->dev, status);
|
fpi_drvcb_capture_started(FP_DEV(imgdev), status);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fp_err("unhandled action %d", imgdev->action);
|
fp_err("unhandled action %d", imgdev->action);
|
||||||
@@ -348,35 +477,44 @@ void fpi_imgdev_activate_complete(struct fp_img_dev *imgdev, int status)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_imgdev_deactivate_complete:
|
||||||
|
* @imgdev: a #fp_img_dev imaging fingerprint device
|
||||||
|
*
|
||||||
|
* Marks a deactivation as complete.
|
||||||
|
*/
|
||||||
void fpi_imgdev_deactivate_complete(struct fp_img_dev *imgdev)
|
void fpi_imgdev_deactivate_complete(struct fp_img_dev *imgdev)
|
||||||
{
|
{
|
||||||
fp_dbg("");
|
enum fp_imgdev_action action;
|
||||||
|
|
||||||
switch (imgdev->action) {
|
G_DEBUG_HERE();
|
||||||
|
|
||||||
|
action = imgdev->action;
|
||||||
|
imgdev->action = IMG_ACTION_NONE;
|
||||||
|
imgdev->action_state = 0;
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
case IMG_ACTION_ENROLL:
|
case IMG_ACTION_ENROLL:
|
||||||
fpi_drvcb_enroll_stopped(imgdev->dev);
|
fpi_drvcb_enroll_stopped(FP_DEV(imgdev));
|
||||||
break;
|
break;
|
||||||
case IMG_ACTION_VERIFY:
|
case IMG_ACTION_VERIFY:
|
||||||
fpi_drvcb_verify_stopped(imgdev->dev);
|
fpi_drvcb_verify_stopped(FP_DEV(imgdev));
|
||||||
break;
|
break;
|
||||||
case IMG_ACTION_IDENTIFY:
|
case IMG_ACTION_IDENTIFY:
|
||||||
fpi_drvcb_identify_stopped(imgdev->dev);
|
fpi_drvcb_identify_stopped(FP_DEV(imgdev));
|
||||||
break;
|
break;
|
||||||
case IMG_ACTION_CAPTURE:
|
case IMG_ACTION_CAPTURE:
|
||||||
fpi_drvcb_capture_stopped(imgdev->dev);
|
fpi_drvcb_capture_stopped(FP_DEV(imgdev));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fp_err("unhandled action %d", imgdev->action);
|
fp_err("unhandled action %d", imgdev->action);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
imgdev->action = IMG_ACTION_NONE;
|
|
||||||
imgdev->action_state = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int fpi_imgdev_get_img_width(struct fp_img_dev *imgdev)
|
int fpi_imgdev_get_img_width(struct fp_img_dev *imgdev)
|
||||||
{
|
{
|
||||||
struct fp_driver *drv = imgdev->dev->drv;
|
struct fp_driver *drv = FP_DEV(imgdev)->drv;
|
||||||
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv);
|
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv);
|
||||||
int width = imgdrv->img_width;
|
int width = imgdrv->img_width;
|
||||||
|
|
||||||
@@ -388,7 +526,7 @@ int fpi_imgdev_get_img_width(struct fp_img_dev *imgdev)
|
|||||||
|
|
||||||
int fpi_imgdev_get_img_height(struct fp_img_dev *imgdev)
|
int fpi_imgdev_get_img_height(struct fp_img_dev *imgdev)
|
||||||
{
|
{
|
||||||
struct fp_driver *drv = imgdev->dev->drv;
|
struct fp_driver *drv = FP_DEV(imgdev)->drv;
|
||||||
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv);
|
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv);
|
||||||
int height = imgdrv->img_height;
|
int height = imgdrv->img_height;
|
||||||
|
|
||||||
@@ -398,19 +536,19 @@ int fpi_imgdev_get_img_height(struct fp_img_dev *imgdev)
|
|||||||
return height;
|
return height;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dev_activate(struct fp_img_dev *imgdev, enum fp_imgdev_state state)
|
static int dev_activate(struct fp_img_dev *imgdev)
|
||||||
{
|
{
|
||||||
struct fp_driver *drv = imgdev->dev->drv;
|
struct fp_driver *drv = FP_DEV(imgdev)->drv;
|
||||||
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv);
|
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv);
|
||||||
|
|
||||||
if (!imgdrv->activate)
|
if (!imgdrv->activate)
|
||||||
return 0;
|
return 0;
|
||||||
return imgdrv->activate(imgdev, state);
|
return imgdrv->activate(imgdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dev_deactivate(struct fp_img_dev *imgdev)
|
static void dev_deactivate(struct fp_img_dev *imgdev)
|
||||||
{
|
{
|
||||||
struct fp_driver *drv = imgdev->dev->drv;
|
struct fp_driver *drv = FP_DEV(imgdev)->drv;
|
||||||
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv);
|
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(drv);
|
||||||
|
|
||||||
if (!imgdrv->deactivate)
|
if (!imgdrv->deactivate)
|
||||||
@@ -420,14 +558,14 @@ static void dev_deactivate(struct fp_img_dev *imgdev)
|
|||||||
|
|
||||||
static int generic_acquire_start(struct fp_dev *dev, int action)
|
static int generic_acquire_start(struct fp_dev *dev, int action)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *imgdev = dev->priv;
|
struct fp_img_dev *imgdev = dev->img_dev;
|
||||||
int r;
|
int r;
|
||||||
fp_dbg("action %d", action);
|
fp_dbg("action %d", action);
|
||||||
imgdev->action = action;
|
imgdev->action = action;
|
||||||
imgdev->action_state = IMG_ACQUIRE_STATE_ACTIVATING;
|
imgdev->action_state = IMG_ACQUIRE_STATE_ACTIVATING;
|
||||||
imgdev->enroll_stage = 0;
|
imgdev->enroll_stage = 0;
|
||||||
|
|
||||||
r = dev_activate(imgdev, IMGDEV_STATE_AWAIT_FINGER_ON);
|
r = dev_activate(imgdev);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
fp_err("activation failed with error %d", r);
|
fp_err("activation failed with error %d", r);
|
||||||
|
|
||||||
@@ -474,7 +612,7 @@ static int img_dev_capture_start(struct fp_dev *dev)
|
|||||||
|
|
||||||
static int img_dev_enroll_stop(struct fp_dev *dev)
|
static int img_dev_enroll_stop(struct fp_dev *dev)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *imgdev = dev->priv;
|
struct fp_img_dev *imgdev = dev->img_dev;
|
||||||
BUG_ON(imgdev->action != IMG_ACTION_ENROLL);
|
BUG_ON(imgdev->action != IMG_ACTION_ENROLL);
|
||||||
generic_acquire_stop(imgdev);
|
generic_acquire_stop(imgdev);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -482,7 +620,7 @@ static int img_dev_enroll_stop(struct fp_dev *dev)
|
|||||||
|
|
||||||
static int img_dev_verify_stop(struct fp_dev *dev, gboolean iterating)
|
static int img_dev_verify_stop(struct fp_dev *dev, gboolean iterating)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *imgdev = dev->priv;
|
struct fp_img_dev *imgdev = dev->img_dev;
|
||||||
BUG_ON(imgdev->action != IMG_ACTION_VERIFY);
|
BUG_ON(imgdev->action != IMG_ACTION_VERIFY);
|
||||||
generic_acquire_stop(imgdev);
|
generic_acquire_stop(imgdev);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -490,7 +628,7 @@ static int img_dev_verify_stop(struct fp_dev *dev, gboolean iterating)
|
|||||||
|
|
||||||
static int img_dev_identify_stop(struct fp_dev *dev, gboolean iterating)
|
static int img_dev_identify_stop(struct fp_dev *dev, gboolean iterating)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *imgdev = dev->priv;
|
struct fp_img_dev *imgdev = dev->img_dev;
|
||||||
BUG_ON(imgdev->action != IMG_ACTION_IDENTIFY);
|
BUG_ON(imgdev->action != IMG_ACTION_IDENTIFY);
|
||||||
generic_acquire_stop(imgdev);
|
generic_acquire_stop(imgdev);
|
||||||
imgdev->identify_match_offset = 0;
|
imgdev->identify_match_offset = 0;
|
||||||
@@ -499,7 +637,7 @@ static int img_dev_identify_stop(struct fp_dev *dev, gboolean iterating)
|
|||||||
|
|
||||||
static int img_dev_capture_stop(struct fp_dev *dev)
|
static int img_dev_capture_stop(struct fp_dev *dev)
|
||||||
{
|
{
|
||||||
struct fp_img_dev *imgdev = dev->priv;
|
struct fp_img_dev *imgdev = dev->img_dev;
|
||||||
BUG_ON(imgdev->action != IMG_ACTION_CAPTURE);
|
BUG_ON(imgdev->action != IMG_ACTION_CAPTURE);
|
||||||
generic_acquire_stop(imgdev);
|
generic_acquire_stop(imgdev);
|
||||||
return 0;
|
return 0;
|
||||||
101
libfprint/fpi-dev-img.h
Normal file
101
libfprint/fpi-dev-img.h
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __FPI_DEV_IMG_H__
|
||||||
|
#define __FPI_DEV_IMG_H__
|
||||||
|
|
||||||
|
#include "fpi-dev.h"
|
||||||
|
#include "fpi-img.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fp_imgdev_action:
|
||||||
|
* @IMG_ACTION_NONE: no action
|
||||||
|
* @IMG_ACTION_ENROLL: device action is enrolling
|
||||||
|
* @IMG_ACTION_VERIFY: device action is verifying
|
||||||
|
* @IMG_ACTION_IDENTIFY: device action is identifying
|
||||||
|
* @IMG_ACTION_CAPTURE: device action is capturing
|
||||||
|
*
|
||||||
|
* The current action being performed by an imaging device. The current
|
||||||
|
* action can be gathered inside the driver using fpi_imgdev_get_action().
|
||||||
|
*/
|
||||||
|
enum fp_imgdev_action {
|
||||||
|
IMG_ACTION_NONE = 0,
|
||||||
|
IMG_ACTION_ENROLL,
|
||||||
|
IMG_ACTION_VERIFY,
|
||||||
|
IMG_ACTION_IDENTIFY,
|
||||||
|
IMG_ACTION_CAPTURE,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fp_imgdev_state:
|
||||||
|
* @IMGDEV_STATE_INACTIVE: inactive
|
||||||
|
* @IMGDEV_STATE_AWAIT_FINGER_ON: waiting for the finger to be pressed or swiped
|
||||||
|
* @IMGDEV_STATE_CAPTURE: capturing an image
|
||||||
|
* @IMGDEV_STATE_AWAIT_FINGER_OFF: waiting for the finger to be removed
|
||||||
|
*
|
||||||
|
* The state of an imaging device while doing a capture. The state is
|
||||||
|
* passed through to the driver using the ::activate() or ::change_state() vfuncs.
|
||||||
|
*/
|
||||||
|
enum fp_imgdev_state {
|
||||||
|
IMGDEV_STATE_INACTIVE,
|
||||||
|
IMGDEV_STATE_AWAIT_FINGER_ON,
|
||||||
|
IMGDEV_STATE_CAPTURE,
|
||||||
|
IMGDEV_STATE_AWAIT_FINGER_OFF,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fp_imgdev_enroll_state:
|
||||||
|
* @IMG_ACQUIRE_STATE_NONE: doing nothing
|
||||||
|
* @IMG_ACQUIRE_STATE_ACTIVATING: activating the device
|
||||||
|
* @IMG_ACQUIRE_STATE_AWAIT_FINGER_ON: waiting for the finger to be pressed or swiped
|
||||||
|
* @IMG_ACQUIRE_STATE_AWAIT_IMAGE: waiting for the image to be captured
|
||||||
|
* @IMG_ACQUIRE_STATE_AWAIT_FINGER_OFF: waiting for the finger to be removed
|
||||||
|
* @IMG_ACQUIRE_STATE_DONE: enrollment has all the images it needs
|
||||||
|
* @IMG_ACQUIRE_STATE_DEACTIVATING: deactivating the device
|
||||||
|
*
|
||||||
|
* The state of an imaging device while enrolling a fingerprint. Given that enrollment
|
||||||
|
* requires multiple captures, a number of those states will be repeated before
|
||||||
|
* the state is @IMG_ACQUIRE_STATE_DONE.
|
||||||
|
*/
|
||||||
|
enum fp_imgdev_enroll_state {
|
||||||
|
IMG_ACQUIRE_STATE_NONE = 0,
|
||||||
|
IMG_ACQUIRE_STATE_ACTIVATING,
|
||||||
|
IMG_ACQUIRE_STATE_AWAIT_FINGER_ON,
|
||||||
|
IMG_ACQUIRE_STATE_AWAIT_IMAGE,
|
||||||
|
IMG_ACQUIRE_STATE_AWAIT_FINGER_OFF,
|
||||||
|
IMG_ACQUIRE_STATE_DONE,
|
||||||
|
IMG_ACQUIRE_STATE_DEACTIVATING,
|
||||||
|
};
|
||||||
|
|
||||||
|
void fpi_imgdev_open_complete(struct fp_img_dev *imgdev, int status);
|
||||||
|
void fpi_imgdev_close_complete(struct fp_img_dev *imgdev);
|
||||||
|
void fpi_imgdev_activate_complete(struct fp_img_dev *imgdev, int status);
|
||||||
|
void fpi_imgdev_deactivate_complete(struct fp_img_dev *imgdev);
|
||||||
|
void fpi_imgdev_report_finger_status(struct fp_img_dev *imgdev,
|
||||||
|
gboolean present);
|
||||||
|
void fpi_imgdev_image_captured(struct fp_img_dev *imgdev, struct fp_img *img);
|
||||||
|
void fpi_imgdev_abort_scan(struct fp_img_dev *imgdev, int result);
|
||||||
|
void fpi_imgdev_session_error(struct fp_img_dev *imgdev, int error);
|
||||||
|
|
||||||
|
enum fp_imgdev_enroll_state fpi_imgdev_get_action_state(struct fp_img_dev *imgdev);
|
||||||
|
enum fp_imgdev_action fpi_imgdev_get_action(struct fp_img_dev *imgdev);
|
||||||
|
int fpi_imgdev_get_action_result(struct fp_img_dev *imgdev);
|
||||||
|
void fpi_imgdev_set_action_result(struct fp_img_dev *imgdev, int action_result);
|
||||||
|
|
||||||
|
#endif
|
||||||
150
libfprint/fpi-dev.c
Normal file
150
libfprint/fpi-dev.c
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
/*
|
||||||
|
* fp_dev types manipulation
|
||||||
|
* 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 "fp_internal.h"
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SECTION:fpi-dev
|
||||||
|
* @title: Device operations
|
||||||
|
* @short_description: Device operation functions
|
||||||
|
*
|
||||||
|
* Those macros and functions will help get access to and from struct #fp_dev,
|
||||||
|
* and struct #fp_img_dev types, as well as get and set the instance struct
|
||||||
|
* data, eg. the structure containing the data specific to each driver.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FP_DEV:
|
||||||
|
* @dev: a struct #fp_img_dev
|
||||||
|
*
|
||||||
|
* Returns the struct #fp_dev associated with @dev, or %NULL on failure.
|
||||||
|
*
|
||||||
|
* Returns: a struct #fp_dev or %NULL
|
||||||
|
*/
|
||||||
|
struct fp_dev *
|
||||||
|
FP_DEV(struct fp_img_dev *dev)
|
||||||
|
{
|
||||||
|
struct fp_img_dev *imgdev;
|
||||||
|
|
||||||
|
g_return_val_if_fail (dev, NULL);
|
||||||
|
imgdev = (struct fp_img_dev *) dev;
|
||||||
|
return imgdev->parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FP_IMG_DEV:
|
||||||
|
* @dev: a struct #fp_dev representing an imaging device.
|
||||||
|
*
|
||||||
|
* Returns a struct #fp_img_dev associated with @dev, or %NULL on failure.
|
||||||
|
*
|
||||||
|
* Returns: a struct #fp_img_dev or %NULL
|
||||||
|
*/
|
||||||
|
struct fp_img_dev *
|
||||||
|
FP_IMG_DEV(struct fp_dev *dev)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (dev, NULL);
|
||||||
|
g_return_val_if_fail (dev->drv, NULL);
|
||||||
|
g_return_val_if_fail (dev->drv->type == DRIVER_IMAGING, NULL);
|
||||||
|
return dev->img_dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fp_dev_set_instance_data:
|
||||||
|
* @dev: a struct #fp_dev
|
||||||
|
* @instance_data: a pointer to the instance data
|
||||||
|
*
|
||||||
|
* Set the instance data for a struct #fp_dev. This is usually a structure
|
||||||
|
* private to the driver used to keep state and pass it as user_data to
|
||||||
|
* asynchronous functions.
|
||||||
|
*
|
||||||
|
* The core does not do any memory management for this data, so the driver
|
||||||
|
* itself will have to create and free its own structure when appropriate.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
fp_dev_set_instance_data (struct fp_dev *dev,
|
||||||
|
void *instance_data)
|
||||||
|
{
|
||||||
|
g_return_if_fail (dev);
|
||||||
|
g_return_if_fail (instance_data != NULL);
|
||||||
|
g_return_if_fail (dev->instance_data == NULL);
|
||||||
|
|
||||||
|
dev->instance_data = instance_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FP_INSTANCE_DATA:
|
||||||
|
* @dev: a struct #fp_dev
|
||||||
|
*
|
||||||
|
* Returns the instance data set using fp_dev_set_instance_data().
|
||||||
|
*/
|
||||||
|
void *
|
||||||
|
FP_INSTANCE_DATA (struct fp_dev *dev)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (dev, NULL);
|
||||||
|
|
||||||
|
return dev->instance_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_dev_get_usb_dev:
|
||||||
|
* @dev: a struct #fp_dev
|
||||||
|
*
|
||||||
|
* Returns the #libusb_device_handle associated with @dev or %NULL
|
||||||
|
* if none are associated.
|
||||||
|
*
|
||||||
|
* Returns: a #libusb_device_handle pointer or %NULL
|
||||||
|
*/
|
||||||
|
libusb_device_handle *
|
||||||
|
fpi_dev_get_usb_dev(struct fp_dev *dev)
|
||||||
|
{
|
||||||
|
return dev->udev;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_dev_set_nr_enroll_stages:
|
||||||
|
* @dev: a struct #fp_dev
|
||||||
|
* @nr_enroll_stages: the number of enroll stages
|
||||||
|
*
|
||||||
|
* Sets the number of enroll stages that this device uses. This is
|
||||||
|
* usually only necessary for primitive devices which have a hard-coded
|
||||||
|
* number of enroll stages baked into their protocol.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
fpi_dev_set_nr_enroll_stages(struct fp_dev *dev,
|
||||||
|
int nr_enroll_stages)
|
||||||
|
{
|
||||||
|
dev->nr_enroll_stages = nr_enroll_stages;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_dev_get_verify_data:
|
||||||
|
* @dev: a struct #fp_dev
|
||||||
|
*
|
||||||
|
* Returns the verify data associated with @dev.
|
||||||
|
* This is usually only necessary for primitive devices which need to
|
||||||
|
* have access to the raw verify data as it might have been stored on disk.
|
||||||
|
*
|
||||||
|
* Returns: a struct #fp_print_data pointer or %NULL
|
||||||
|
*/
|
||||||
|
struct fp_print_data *
|
||||||
|
fpi_dev_get_verify_data(struct fp_dev *dev)
|
||||||
|
{
|
||||||
|
return dev->verify_data;
|
||||||
|
}
|
||||||
47
libfprint/fpi-dev.h
Normal file
47
libfprint/fpi-dev.h
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __FPI_DEV_H__
|
||||||
|
#define __FPI_DEV_H__
|
||||||
|
|
||||||
|
#include <libusb.h>
|
||||||
|
#include <fprint.h>
|
||||||
|
|
||||||
|
struct fp_dev;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fp_img_dev:
|
||||||
|
*
|
||||||
|
* #fp_img_dev is an opaque structure type. You must access it using the
|
||||||
|
* appropriate functions.
|
||||||
|
*/
|
||||||
|
struct fp_img_dev;
|
||||||
|
|
||||||
|
struct fp_dev *FP_DEV (struct fp_img_dev *dev);
|
||||||
|
struct fp_img_dev *FP_IMG_DEV (struct fp_dev *dev);
|
||||||
|
|
||||||
|
void fp_dev_set_instance_data (struct fp_dev *dev,
|
||||||
|
void *instance_data);
|
||||||
|
void *FP_INSTANCE_DATA (struct fp_dev *dev);
|
||||||
|
|
||||||
|
libusb_device_handle *fpi_dev_get_usb_dev(struct fp_dev *dev);
|
||||||
|
void fpi_dev_set_nr_enroll_stages(struct fp_dev *dev,
|
||||||
|
int nr_enroll_stages);
|
||||||
|
struct fp_print_data *fpi_dev_get_verify_data(struct fp_dev *dev);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -23,7 +23,19 @@
|
|||||||
|
|
||||||
#include "fp_internal.h"
|
#include "fp_internal.h"
|
||||||
|
|
||||||
struct fp_img *fpi_im_resize(struct fp_img *img, unsigned int w_factor, unsigned int h_factor)
|
/**
|
||||||
|
* fpi_img_resize:
|
||||||
|
* @img: an #fp_img image
|
||||||
|
* @w_factor: horizontal factor to resize the image by
|
||||||
|
* @h_factor: vertical factor to resize the image by
|
||||||
|
*
|
||||||
|
* Resizes the #fp_img image by scaling it by @w_factor times horizontally
|
||||||
|
* and @h_factor times vertically.
|
||||||
|
*
|
||||||
|
* Returns: a newly allocated #fp_img, the original @img will not be modified
|
||||||
|
* and will also need to be freed
|
||||||
|
*/
|
||||||
|
struct fp_img *fpi_img_resize(struct fp_img *img, unsigned int w_factor, unsigned int h_factor)
|
||||||
{
|
{
|
||||||
int new_width = img->width * w_factor;
|
int new_width = img->width * w_factor;
|
||||||
int new_height = img->height * h_factor;
|
int new_height = img->height * h_factor;
|
||||||
@@ -28,23 +28,46 @@
|
|||||||
#include "nbis/include/bozorth.h"
|
#include "nbis/include/bozorth.h"
|
||||||
#include "nbis/include/lfs.h"
|
#include "nbis/include/lfs.h"
|
||||||
|
|
||||||
/** @defgroup img Image operations
|
/**
|
||||||
|
* SECTION:img
|
||||||
|
* @title: Image operations
|
||||||
|
* @short_description: Image operation functions
|
||||||
|
*
|
||||||
* libfprint offers several ways of retrieving images from imaging devices,
|
* libfprint offers several ways of retrieving images from imaging devices,
|
||||||
* one example being the fp_dev_img_capture() function. The functions
|
* one example being the fp_dev_img_capture() function. The functions
|
||||||
* documented below allow you to work with such images.
|
* documented below allow you to work with such images.
|
||||||
*
|
*
|
||||||
* \section img_fmt Image format
|
* # Image format # {#img_fmt}
|
||||||
* All images are represented as 8-bit greyscale data.
|
* All images are represented as 8-bit greyscale data.
|
||||||
*
|
*
|
||||||
* \section img_std Image standardization
|
* # Image standardization # {#img_std}
|
||||||
* In some contexts, images you are provided through libfprint are raw images
|
* In some contexts, images you are provided through libfprint are raw images
|
||||||
* from the hardware. The orientation of these varies from device-to-device,
|
* from the hardware. The orientation of these varies from device-to-device,
|
||||||
* as does the color scheme (black-on-white or white-on-black?). libfprint
|
* as does the color scheme (black-on-white or white-on-black?). libfprint
|
||||||
* provides the fp_img_standardize function to convert images into standard
|
* provides the fp_img_standardize() function to convert images into standard
|
||||||
* form, which is defined to be: finger flesh as black on white surroundings,
|
* form, which is defined to be: finger flesh as black on white surroundings,
|
||||||
* natural upright orientation.
|
* natural upright orientation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SECTION:fpi-img
|
||||||
|
* @title: Driver Image operations
|
||||||
|
* @short_description: Driver image operation functions
|
||||||
|
*
|
||||||
|
* Those are the driver-specific helpers for #fp_img manipulation. See #fp_img's
|
||||||
|
* documentation for more information about data formats, and their uses in
|
||||||
|
* front-end applications.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_img_new:
|
||||||
|
* @length: the length of data to allocate
|
||||||
|
*
|
||||||
|
* Creates a new #fp_img structure with @length bytes of data allocated
|
||||||
|
* to hold the image.
|
||||||
|
*
|
||||||
|
* Returns: a new #fp_img to free with fp_img_free()
|
||||||
|
*/
|
||||||
struct fp_img *fpi_img_new(size_t length)
|
struct fp_img *fpi_img_new(size_t length)
|
||||||
{
|
{
|
||||||
struct fp_img *img = g_malloc0(sizeof(*img) + length);
|
struct fp_img *img = g_malloc0(sizeof(*img) + length);
|
||||||
@@ -53,9 +76,19 @@ struct fp_img *fpi_img_new(size_t length)
|
|||||||
return img;
|
return img;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_img_new_for_imgdev:
|
||||||
|
* @imgdev: a #fp_img_dev imaging fingerprint device
|
||||||
|
*
|
||||||
|
* Creates a new #fp_img structure, like fpi_img_new(), but uses the
|
||||||
|
* driver's advertised height and width to calculate the size of the
|
||||||
|
* length of data to allocate.
|
||||||
|
*
|
||||||
|
* Returns: a new #fp_img to free with fp_img_free()
|
||||||
|
*/
|
||||||
struct fp_img *fpi_img_new_for_imgdev(struct fp_img_dev *imgdev)
|
struct fp_img *fpi_img_new_for_imgdev(struct fp_img_dev *imgdev)
|
||||||
{
|
{
|
||||||
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(imgdev->dev->drv);
|
struct fp_img_driver *imgdrv = fpi_driver_to_img_driver(FP_DEV(imgdev)->drv);
|
||||||
int width = imgdrv->img_width;
|
int width = imgdrv->img_width;
|
||||||
int height = imgdrv->img_height;
|
int height = imgdrv->img_height;
|
||||||
struct fp_img *img = fpi_img_new(width * height);
|
struct fp_img *img = fpi_img_new(width * height);
|
||||||
@@ -64,27 +97,55 @@ struct fp_img *fpi_img_new_for_imgdev(struct fp_img_dev *imgdev)
|
|||||||
return img;
|
return img;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_img_is_sane:
|
||||||
|
* @img: a #fp_img image
|
||||||
|
*
|
||||||
|
* Checks whether an #fp_img structure passes some basic checks, such
|
||||||
|
* as length, width and height being non-zero, and the buffer being
|
||||||
|
* big enough to hold the image of said size.
|
||||||
|
*
|
||||||
|
* Returns: %TRUE if the image is sane, %FALSE otherwise
|
||||||
|
*/
|
||||||
gboolean fpi_img_is_sane(struct fp_img *img)
|
gboolean fpi_img_is_sane(struct fp_img *img)
|
||||||
{
|
{
|
||||||
|
guint len;
|
||||||
|
|
||||||
/* basic checks */
|
/* basic checks */
|
||||||
if (!img->length || !img->width || !img->height)
|
if (!img->length || img->width <= 0 || img->height <= 0)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
/* buffer is big enough? */
|
/* Are width and height just too big? */
|
||||||
if ((img->length * img->height) < img->length)
|
if (!g_uint_checked_mul(&len, img->width, img->height) ||
|
||||||
|
len > G_MAXINT)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* buffer big enough? */
|
||||||
|
if (len > img->length)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct fp_img *fpi_img_resize(struct fp_img *img, size_t newsize)
|
/**
|
||||||
|
* fpi_img_realloc:
|
||||||
|
* @img: an #fp_img image
|
||||||
|
* @newsize: the new length of the image
|
||||||
|
*
|
||||||
|
* Changes the size of the data part of the #fp_img.
|
||||||
|
*
|
||||||
|
* Returns: the modified #fp_img, the same as the first argument to this function
|
||||||
|
*/
|
||||||
|
struct fp_img *fpi_img_realloc(struct fp_img *img, size_t newsize)
|
||||||
{
|
{
|
||||||
return g_realloc(img, sizeof(*img) + newsize);
|
return g_realloc(img, sizeof(*img) + newsize);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \ingroup img
|
/**
|
||||||
|
* fp_img_free:
|
||||||
|
* @img: the image to destroy. If %NULL, function simply returns.
|
||||||
|
*
|
||||||
* Frees an image. Must be called when you are finished working with an image.
|
* Frees an image. Must be called when you are finished working with an image.
|
||||||
* \param img the image to destroy. If NULL, function simply returns.
|
|
||||||
*/
|
*/
|
||||||
API_EXPORTED void fp_img_free(struct fp_img *img)
|
API_EXPORTED void fp_img_free(struct fp_img *img)
|
||||||
{
|
{
|
||||||
@@ -98,43 +159,55 @@ API_EXPORTED void fp_img_free(struct fp_img *img)
|
|||||||
g_free(img);
|
g_free(img);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \ingroup img
|
/**
|
||||||
|
* fp_img_get_height:
|
||||||
|
* @img: an image
|
||||||
|
*
|
||||||
* Gets the pixel height of an image.
|
* Gets the pixel height of an image.
|
||||||
* \param img an image
|
*
|
||||||
* \returns the height of the image
|
* Returns: the height of the image
|
||||||
*/
|
*/
|
||||||
API_EXPORTED int fp_img_get_height(struct fp_img *img)
|
API_EXPORTED int fp_img_get_height(struct fp_img *img)
|
||||||
{
|
{
|
||||||
return img->height;
|
return img->height;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \ingroup img
|
/**
|
||||||
|
* fp_img_get_width:
|
||||||
|
* @img: an image
|
||||||
|
*
|
||||||
* Gets the pixel width of an image.
|
* Gets the pixel width of an image.
|
||||||
* \param img an image
|
*
|
||||||
* \returns the width of the image
|
* Returns: the width of the image
|
||||||
*/
|
*/
|
||||||
API_EXPORTED int fp_img_get_width(struct fp_img *img)
|
API_EXPORTED int fp_img_get_width(struct fp_img *img)
|
||||||
{
|
{
|
||||||
return img->width;
|
return img->width;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \ingroup img
|
/**
|
||||||
|
* fp_img_get_data:
|
||||||
|
* @img: an image
|
||||||
|
*
|
||||||
* Gets the greyscale data for an image. This data must not be modified or
|
* Gets the greyscale data for an image. This data must not be modified or
|
||||||
* freed, and must not be used after fp_img_free() has been called.
|
* freed, and must not be used after fp_img_free() has been called.
|
||||||
* \param img an image
|
*
|
||||||
* \returns a pointer to libfprint's internal data for the image
|
* Returns: a pointer to libfprint's internal data for the image
|
||||||
*/
|
*/
|
||||||
API_EXPORTED unsigned char *fp_img_get_data(struct fp_img *img)
|
API_EXPORTED unsigned char *fp_img_get_data(struct fp_img *img)
|
||||||
{
|
{
|
||||||
return img->data;
|
return img->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \ingroup img
|
/**
|
||||||
|
* fp_img_save_to_file:
|
||||||
|
* @img: the image to save
|
||||||
|
* @path: the path to save the image. Existing files will be overwritten.
|
||||||
|
*
|
||||||
* A quick convenience function to save an image to a file in
|
* A quick convenience function to save an image to a file in
|
||||||
* <a href="http://netpbm.sourceforge.net/doc/pgm.html">PGM format</a>.
|
* [PGM format](http://netpbm.sourceforge.net/doc/pgm.html).
|
||||||
* \param img the image to save
|
*
|
||||||
* \param path the path to save the image. Existing files will be overwritten.
|
* Returns: 0 on success, non-zero on error.
|
||||||
* \returns 0 on success, non-zero on error.
|
|
||||||
*/
|
*/
|
||||||
API_EXPORTED int fp_img_save_to_file(struct fp_img *img, char *path)
|
API_EXPORTED int fp_img_save_to_file(struct fp_img *img, char *path)
|
||||||
{
|
{
|
||||||
@@ -149,12 +222,14 @@ API_EXPORTED int fp_img_save_to_file(struct fp_img *img, char *path)
|
|||||||
|
|
||||||
r = fprintf(fd, "P5 %d %d 255\n", img->width, img->height);
|
r = fprintf(fd, "P5 %d %d 255\n", img->width, img->height);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
|
fclose(fd);
|
||||||
fp_err("pgm header write failed, error %d", r);
|
fp_err("pgm header write failed, error %d", r);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = fwrite(img->data, 1, write_size, fd);
|
r = fwrite(img->data, 1, write_size, fd);
|
||||||
if (r < write_size) {
|
if (r < write_size) {
|
||||||
|
fclose(fd);
|
||||||
fp_err("short write (%d)", r);
|
fp_err("short write (%d)", r);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
@@ -209,12 +284,14 @@ static void invert_colors(struct fp_img *img)
|
|||||||
img->data[i] = 0xff - img->data[i];
|
img->data[i] = 0xff - img->data[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \ingroup img
|
/**
|
||||||
* \ref img_std "Standardizes" an image by normalizing its orientation, colors,
|
* fp_img_standardize:
|
||||||
|
* @img: the image to standardize
|
||||||
|
*
|
||||||
|
* [Standardizes](libfprint-Image-operations.html#img_std) an image by normalizing its orientation, colors,
|
||||||
* etc. It is safe to call this multiple times on an image, libfprint keeps
|
* etc. It is safe to call this multiple times on an image, libfprint keeps
|
||||||
* track of the work it needs to do to make an image standard and will not
|
* track of the work it needs to do to make an image standard and will not
|
||||||
* perform these operations more than once for a given image.
|
* perform these operations more than once for a given image.
|
||||||
* \param img the image to standardize
|
|
||||||
*/
|
*/
|
||||||
API_EXPORTED void fp_img_standardize(struct fp_img *img)
|
API_EXPORTED void fp_img_standardize(struct fp_img *img)
|
||||||
{
|
{
|
||||||
@@ -241,9 +318,8 @@ static void minutiae_to_xyt(struct fp_minutiae *minutiae, int bwidth,
|
|||||||
struct minutiae_struct c[MAX_FILE_MINUTIAE];
|
struct minutiae_struct c[MAX_FILE_MINUTIAE];
|
||||||
struct xyt_struct *xyt = (struct xyt_struct *) buf;
|
struct xyt_struct *xyt = (struct xyt_struct *) buf;
|
||||||
|
|
||||||
/* FIXME: only considers first 150 minutiae (MAX_FILE_MINUTIAE) */
|
/* struct xyt_struct uses arrays of MAX_BOZORTH_MINUTIAE (200) */
|
||||||
/* nist does weird stuff with 150 vs 1000 limits */
|
int nmin = min(minutiae->num, MAX_BOZORTH_MINUTIAE);
|
||||||
int nmin = min(minutiae->num, MAX_FILE_MINUTIAE);
|
|
||||||
|
|
||||||
for (i = 0; i < nmin; i++){
|
for (i = 0; i < nmin; i++){
|
||||||
minutia = minutiae->list[i];
|
minutia = minutiae->list[i];
|
||||||
@@ -267,7 +343,10 @@ static void minutiae_to_xyt(struct fp_minutiae *minutiae, int bwidth,
|
|||||||
xyt->nrows = nmin;
|
xyt->nrows = nmin;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fpi_img_detect_minutiae(struct fp_img *img)
|
#define FP_IMG_STANDARDIZATION_FLAGS (FP_IMG_V_FLIPPED | FP_IMG_H_FLIPPED \
|
||||||
|
| FP_IMG_COLORS_INVERTED)
|
||||||
|
|
||||||
|
static int fpi_img_detect_minutiae(struct fp_img *img)
|
||||||
{
|
{
|
||||||
struct fp_minutiae *minutiae;
|
struct fp_minutiae *minutiae;
|
||||||
int r;
|
int r;
|
||||||
@@ -279,7 +358,7 @@ int fpi_img_detect_minutiae(struct fp_img *img)
|
|||||||
GTimer *timer;
|
GTimer *timer;
|
||||||
|
|
||||||
if (img->flags & FP_IMG_STANDARDIZATION_FLAGS) {
|
if (img->flags & FP_IMG_STANDARDIZATION_FLAGS) {
|
||||||
fp_err("cant detect minutiae for non-standardized image");
|
fp_err("Cannot detect minutiae for non-standardized images");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -326,9 +405,9 @@ int fpi_img_to_print_data(struct fp_img_dev *imgdev, struct fp_img *img,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME: space is wasted if we dont hit the max minutiae count. would
|
/* FIXME: space is wasted if we don't hit the max minutiae count. would
|
||||||
* be good to make this dynamic. */
|
* be good to make this dynamic. */
|
||||||
print = fpi_print_data_new(imgdev->dev);
|
print = fpi_print_data_new(FP_DEV(imgdev));
|
||||||
item = fpi_print_data_item_new(sizeof(struct xyt_struct));
|
item = fpi_print_data_item_new(sizeof(struct xyt_struct));
|
||||||
print->type = PRINT_DATA_NBIS_MINUTIAE;
|
print->type = PRINT_DATA_NBIS_MINUTIAE;
|
||||||
minutiae_to_xyt(img->minutiae, img->width, img->height, item->data);
|
minutiae_to_xyt(img->minutiae, img->width, img->height, item->data);
|
||||||
@@ -416,23 +495,25 @@ int fpi_img_compare_print_data_to_gallery(struct fp_print_data *print,
|
|||||||
return FP_VERIFY_NO_MATCH;
|
return FP_VERIFY_NO_MATCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \ingroup img
|
/**
|
||||||
|
* fp_img_binarize:
|
||||||
|
* @img: a standardized image
|
||||||
|
*
|
||||||
* Get a binarized form of a standardized scanned image. This is where the
|
* Get a binarized form of a standardized scanned image. This is where the
|
||||||
* fingerprint image has been "enhanced" and is a set of pure black ridges
|
* fingerprint image has been "enhanced" and is a set of pure black ridges
|
||||||
* on a pure white background. Internally, image processing happens on top
|
* on a pure white background. Internally, image processing happens on top
|
||||||
* of the binarized image.
|
* of the binarized image.
|
||||||
*
|
*
|
||||||
* The image must have been \ref img_std "standardized" otherwise this function
|
* The image must have been [standardized](libfprint-Image-operations.html#img_std)
|
||||||
* will fail.
|
* otherwise this function will fail.
|
||||||
*
|
*
|
||||||
* It is safe to binarize an image and free the original while continuing
|
* It is safe to binarize an image and free the original while continuing
|
||||||
* to use the binarized version.
|
* to use the binarized version.
|
||||||
*
|
*
|
||||||
* You cannot binarize an image twice.
|
* You cannot binarize an image twice.
|
||||||
*
|
*
|
||||||
* \param img a standardized image
|
* Returns: a new image representing the binarized form of the original, or
|
||||||
* \returns a new image representing the binarized form of the original, or
|
* %NULL on error. Must be freed with fp_img_free() after use.
|
||||||
* NULL on error. Must be freed with fp_img_free() after use.
|
|
||||||
*/
|
*/
|
||||||
API_EXPORTED struct fp_img *fp_img_binarize(struct fp_img *img)
|
API_EXPORTED struct fp_img *fp_img_binarize(struct fp_img *img)
|
||||||
{
|
{
|
||||||
@@ -464,15 +545,19 @@ API_EXPORTED struct fp_img *fp_img_binarize(struct fp_img *img)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \ingroup img
|
/**
|
||||||
|
* fp_img_get_minutiae:
|
||||||
|
* @img: a standardized image
|
||||||
|
* @nr_minutiae: an output location to store minutiae list length
|
||||||
|
*
|
||||||
* Get a list of minutiae detected in an image. A minutia point is a feature
|
* Get a list of minutiae detected in an image. A minutia point is a feature
|
||||||
* detected on a fingerprint, typically where ridges end or split.
|
* detected on a fingerprint, typically where ridges end or split.
|
||||||
* libfprint's image processing code relies upon comparing sets of minutiae,
|
* libfprint's image processing code relies upon comparing sets of minutiae,
|
||||||
* so accurate placement of minutia points is critical for good imaging
|
* so accurate placement of minutia points is critical for good imaging
|
||||||
* performance.
|
* performance.
|
||||||
*
|
*
|
||||||
* The image must have been \ref img_std "standardized" otherwise this function
|
* The image must have been [standardized](libfprint-Image-operations.html#img_std)
|
||||||
* will fail.
|
* otherwise this function will fail.
|
||||||
*
|
*
|
||||||
* You cannot pass a binarized image to this function. Instead, pass the
|
* You cannot pass a binarized image to this function. Instead, pass the
|
||||||
* original image.
|
* original image.
|
||||||
@@ -482,9 +567,7 @@ API_EXPORTED struct fp_img *fp_img_binarize(struct fp_img *img)
|
|||||||
* valid while the parent image has not been freed, and the minutiae data
|
* valid while the parent image has not been freed, and the minutiae data
|
||||||
* must not be modified or freed.
|
* must not be modified or freed.
|
||||||
*
|
*
|
||||||
* \param img a standardized image
|
* Returns: a list of minutiae points. Must not be modified or freed.
|
||||||
* \param nr_minutiae an output location to store minutiae list length
|
|
||||||
* \returns a list of minutiae points. Must not be modified or freed.
|
|
||||||
*/
|
*/
|
||||||
API_EXPORTED struct fp_minutia **fp_img_get_minutiae(struct fp_img *img,
|
API_EXPORTED struct fp_minutia **fp_img_get_minutiae(struct fp_img *img,
|
||||||
int *nr_minutiae)
|
int *nr_minutiae)
|
||||||
@@ -508,3 +591,92 @@ API_EXPORTED struct fp_minutia **fp_img_get_minutiae(struct fp_img *img,
|
|||||||
return img->minutiae->list;
|
return img->minutiae->list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fp_minutia_get_coords:
|
||||||
|
* @minutia: a struct #fp_minutia
|
||||||
|
* @coord_x: the return variable for the X coordinate of the minutia
|
||||||
|
* @coord_y: the return variable for the Y coordinate of the minutia
|
||||||
|
*
|
||||||
|
* Sets @coord_x and @coord_y to be the coordinates of the detected minutia, so it
|
||||||
|
* can be presented in a more verbose user interface. This is usually only
|
||||||
|
* used for debugging purposes.
|
||||||
|
*
|
||||||
|
* Returns: 0 on success, -1 on error.
|
||||||
|
*/
|
||||||
|
API_EXPORTED int fp_minutia_get_coords(struct fp_minutia *minutia, int *coord_x, int *coord_y)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (minutia != NULL, -1);
|
||||||
|
g_return_val_if_fail (coord_x != NULL, -1);
|
||||||
|
g_return_val_if_fail (coord_y != NULL, -1);
|
||||||
|
|
||||||
|
*coord_x = minutia->x;
|
||||||
|
*coord_y = minutia->y;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_std_sq_dev:
|
||||||
|
* @buf: buffer (usually bitmap, one byte per pixel)
|
||||||
|
* @size: size of @buffer
|
||||||
|
*
|
||||||
|
* Calculates the squared standard deviation of the individual
|
||||||
|
* pixels in the buffer, as per the following formula:
|
||||||
|
* |[<!-- -->
|
||||||
|
* mean = sum (buf[0..size]) / size
|
||||||
|
* sq_dev = sum ((buf[0.size] - mean) ^ 2)
|
||||||
|
* ]|
|
||||||
|
* This function is usually used to determine whether image
|
||||||
|
* is empty.
|
||||||
|
*
|
||||||
|
* Returns: the squared standard deviation for @buffer
|
||||||
|
*/
|
||||||
|
int fpi_std_sq_dev(const unsigned char *buf, int size)
|
||||||
|
{
|
||||||
|
int res = 0, mean = 0, i;
|
||||||
|
|
||||||
|
if (size > (INT_MAX / 65536)) {
|
||||||
|
fp_err("%s: we might get an overflow!", __func__);
|
||||||
|
return -EOVERFLOW;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < size; i++)
|
||||||
|
mean += buf[i];
|
||||||
|
|
||||||
|
mean /= size;
|
||||||
|
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
int dev = (int)buf[i] - mean;
|
||||||
|
res += dev*dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res / size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_mean_sq_diff_norm:
|
||||||
|
* @buf1: buffer (usually bitmap, one byte per pixel)
|
||||||
|
* @buf2: buffer (usually bitmap, one byte per pixel)
|
||||||
|
* @size: buffer size of smallest buffer
|
||||||
|
*
|
||||||
|
* This function calculates the normalized mean square difference of
|
||||||
|
* two buffers, usually two lines, as per the following formula:
|
||||||
|
* |[<!-- -->
|
||||||
|
* sq_diff = sum ((buf1[0..size] - buf2[0..size]) ^ 2) / size
|
||||||
|
* ]|
|
||||||
|
*
|
||||||
|
* This functions is usually used to get numerical difference
|
||||||
|
* between two images.
|
||||||
|
*
|
||||||
|
* Returns: the normalized mean squared difference between @buf1 and @buf2
|
||||||
|
*/
|
||||||
|
int fpi_mean_sq_diff_norm(unsigned char *buf1, unsigned char *buf2, int size)
|
||||||
|
{
|
||||||
|
int res = 0, i;
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
int dev = (int)buf1[i] - (int)buf2[i];
|
||||||
|
res += dev * dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res / size;
|
||||||
|
}
|
||||||
85
libfprint/fpi-img.h
Normal file
85
libfprint/fpi-img.h
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __FPI_IMG_H__
|
||||||
|
#define __FPI_IMG_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
struct fp_minutiae;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FpiImgFlags:
|
||||||
|
* @FP_IMG_V_FLIPPED: the image is vertically flipped
|
||||||
|
* @FP_IMG_H_FLIPPED: the image is horizontally flipped
|
||||||
|
* @FP_IMG_COLORS_INVERTED: the colours are inverted
|
||||||
|
* @FP_IMG_BINARIZED_FORM: binarised image, see fp_img_binarize()
|
||||||
|
* @FP_IMG_PARTIAL: the image is partial, useful for driver to keep track
|
||||||
|
* of incomplete captures
|
||||||
|
*
|
||||||
|
* Flags used in the #fp_img structure to describe the image contained
|
||||||
|
* into the structure. Note that a number of functions will refuse to
|
||||||
|
* handle images which haven't been standardised through fp_img_standardize()
|
||||||
|
* (meaning the @FP_IMG_V_FLIPPED, @FP_IMG_H_FLIPPED and @FP_IMG_COLORS_INVERTED
|
||||||
|
* should all be unset when the image needs to be analysed).
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
FP_IMG_V_FLIPPED = 1 << 0,
|
||||||
|
FP_IMG_H_FLIPPED = 1 << 1,
|
||||||
|
FP_IMG_COLORS_INVERTED = 1 << 2,
|
||||||
|
FP_IMG_BINARIZED_FORM = 1 << 3,
|
||||||
|
FP_IMG_PARTIAL = 1 << 4
|
||||||
|
} FpiImgFlags;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fp_img:
|
||||||
|
* @width: the width of the image
|
||||||
|
* @height: the height of the image
|
||||||
|
* @length: the length of the data associated with the image
|
||||||
|
* @flags: @FpiImgFlags flags describing the image contained in the structure
|
||||||
|
* @minutiae: an opaque structure representing the detected minutiae
|
||||||
|
* @binarized: the binarized image data
|
||||||
|
* @data: the start of the image data, which will be of @length size.
|
||||||
|
*
|
||||||
|
* A structure representing a captured, or processed image. The @flags member
|
||||||
|
* will show its current state, including whether whether the binarized form
|
||||||
|
* if present, whether it is complete, and whether it needs particular changes
|
||||||
|
* before being processed.
|
||||||
|
*/
|
||||||
|
struct fp_img {
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
size_t length;
|
||||||
|
FpiImgFlags flags;
|
||||||
|
/*< private >*/
|
||||||
|
struct fp_minutiae *minutiae;
|
||||||
|
/*< public >*/
|
||||||
|
unsigned char *binarized;
|
||||||
|
unsigned char data[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fp_img *fpi_img_new(size_t length);
|
||||||
|
struct fp_img *fpi_img_new_for_imgdev(struct fp_img_dev *imgdev);
|
||||||
|
struct fp_img *fpi_img_realloc(struct fp_img *img, size_t newsize);
|
||||||
|
struct fp_img *fpi_img_resize(struct fp_img *img, unsigned int w_factor, unsigned int h_factor);
|
||||||
|
|
||||||
|
int fpi_std_sq_dev(const unsigned char *buf, int size);
|
||||||
|
int fpi_mean_sq_diff_norm(unsigned char *buf1, unsigned char *buf2, int size);
|
||||||
|
|
||||||
|
#endif
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user