Line | Branch | Exec | Source |
---|---|---|---|
1 | /* | ||
2 | * vfs301/vfs300 fingerprint reader driver | ||
3 | * https://github.com/andree182/vfs301 | ||
4 | * | ||
5 | * Copyright (c) 2011-2012 Andrej Krutak <dev@andree.sk> | ||
6 | * | ||
7 | * This library is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU Lesser General Public | ||
9 | * License as published by the Free Software Foundation; either | ||
10 | * version 2.1 of the License, or (at your option) any later version. | ||
11 | * | ||
12 | * This library is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * Lesser General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU Lesser General Public | ||
18 | * License along with this library; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
20 | */ | ||
21 | |||
22 | /* | ||
23 | * TODO: | ||
24 | * - async communication everywhere :) | ||
25 | * - protocol decyphering | ||
26 | * - what is needed and what is redundant | ||
27 | * - is some part of the initial data the firmware? | ||
28 | * - describe some interesting structures better | ||
29 | */ | ||
30 | #include <errno.h> | ||
31 | #include <string.h> | ||
32 | #include <stdio.h> | ||
33 | #include <unistd.h> | ||
34 | #include <stdlib.h> | ||
35 | #include <glib.h> | ||
36 | |||
37 | #include "fpi-usb-transfer.h" | ||
38 | #include "vfs301.h" | ||
39 | #include "vfs301_proto_fragments.h" | ||
40 | |||
41 | /************************** USB STUFF *****************************************/ | ||
42 | |||
43 | #ifdef DEBUG | ||
44 | static void | ||
45 | usb_print_packet (int dir, GError *error, const guint8 *data, int length) | ||
46 | { | ||
47 | fprintf (stderr, "%s, error %s, len %d\n", dir ? "send" : "recv", error ? error->message : "-", length); | ||
48 | |||
49 | #ifdef PRINT_VERBOSE | ||
50 | int i; | ||
51 | |||
52 | for (i = 0; i < MIN (length, 128); i++) | ||
53 | { | ||
54 | fprintf (stderr, "%.2X ", data[i]); | ||
55 | if (i % 8 == 7) | ||
56 | fprintf (stderr, " "); | ||
57 | if (i % 32 == 31) | ||
58 | fprintf (stderr, "\n"); | ||
59 | } | ||
60 | #endif | ||
61 | |||
62 | fprintf (stderr, "\n"); | ||
63 | } | ||
64 | #endif | ||
65 | |||
66 | static void | ||
67 | 51 | usb_recv (FpDeviceVfs301 *dev, guint8 endpoint, int max_bytes, FpiUsbTransfer **out, GError **error) | |
68 | { | ||
69 | 51 | GError *err = NULL; | |
70 | |||
71 | 102 | g_autoptr(FpiUsbTransfer) transfer = NULL; | |
72 | |||
73 | /* XXX: This function swallows any transfer errors, that is obviously | ||
74 | * quite bad (it used to assert on no-error)! */ | ||
75 | |||
76 | 51 | transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); | |
77 | 51 | transfer->short_is_error = TRUE; | |
78 | 51 | fpi_usb_transfer_fill_bulk (transfer, endpoint, max_bytes); | |
79 | |||
80 | 51 | fpi_usb_transfer_submit_sync (transfer, VFS301_DEFAULT_WAIT_TIMEOUT, &err); | |
81 | |||
82 | #ifdef DEBUG | ||
83 | usb_print_packet (0, err, transfer->buffer, transfer->actual_length); | ||
84 | #endif | ||
85 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 51 times.
|
51 | if (err) |
86 | { | ||
87 | ✗ | if (!error) | |
88 | ✗ | g_warning ("Unhandled receive error: %s", err->message); | |
89 | ✗ | g_propagate_error (error, err); | |
90 | } | ||
91 | |||
92 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 49 times.
|
51 | if (out) |
93 | 2 | *out = g_steal_pointer (&transfer); | |
94 | 51 | } | |
95 | |||
96 | FP_GNUC_ACCESS (read_only, 2, 3) | ||
97 | static void | ||
98 | 35 | usb_send (FpDeviceVfs301 *dev, const guint8 *data, gssize length, GError **error) | |
99 | { | ||
100 | 35 | GError *err = NULL; | |
101 | |||
102 | 70 | g_autoptr(FpiUsbTransfer) transfer = NULL; | |
103 | |||
104 | /* XXX: This function swallows any transfer errors, that is obviously | ||
105 | * quite bad (it used to assert on no-error)! */ | ||
106 | |||
107 | 35 | transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); | |
108 | 35 | transfer->short_is_error = TRUE; | |
109 | 35 | fpi_usb_transfer_fill_bulk_full (transfer, VFS301_SEND_ENDPOINT, (guint8 *) data, length, g_free); | |
110 | |||
111 | 35 | fpi_usb_transfer_submit_sync (transfer, VFS301_DEFAULT_WAIT_TIMEOUT, &err); | |
112 | |||
113 | #ifdef DEBUG | ||
114 | usb_print_packet (1, err, data, length); | ||
115 | #endif | ||
116 | |||
117 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
|
35 | if (err) |
118 | { | ||
119 | ✗ | g_warning ("Error while sending data, continuing anyway: %s", err->message); | |
120 | ✗ | g_propagate_error (error, err); | |
121 | } | ||
122 | 35 | } | |
123 | |||
124 | /************************** OUT MESSAGES GENERATION ***************************/ | ||
125 | |||
126 | static guint8 * | ||
127 | 2 | vfs301_proto_generate_0B (int subtype, gssize *len) | |
128 | { | ||
129 | 2 | guint8 *res = g_malloc0 (39); | |
130 | 2 | guint8 *data = res; | |
131 | |||
132 | 2 | *data = 0x0B; | |
133 | 2 | *len = 1; | |
134 | 2 | data++; | |
135 | |||
136 | 2 | *len += 38; | |
137 | |||
138 | 2 | data[20] = subtype; | |
139 | |||
140 |
2/3✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
2 | switch (subtype) |
141 | { | ||
142 | 1 | case 0x04: | |
143 | 1 | data[34] = 0x9F; | |
144 | 1 | break; | |
145 | |||
146 | 1 | case 0x05: | |
147 | 1 | data[34] = 0xAB; | |
148 | /* NOTE: There was a len++ here, which could never do anything */ | ||
149 | 1 | break; | |
150 | |||
151 | ✗ | default: | |
152 | ✗ | g_assert_not_reached (); | |
153 | break; | ||
154 | } | ||
155 | |||
156 | 2 | return res; | |
157 | } | ||
158 | |||
159 | #define HEX_TO_INT(c) \ | ||
160 | (((c) >= '0' && (c) <= '9') ? ((c) - '0') : ((c) - 'A' + 10)) | ||
161 | |||
162 | static guint8 * | ||
163 | 12 | translate_str (const char **srcL, gssize *len) | |
164 | { | ||
165 | 12 | guint8 *res = NULL; | |
166 | 12 | guint8 *dst; | |
167 | 12 | const char **src_pos; | |
168 | 12 | const char *src; | |
169 | 12 | gssize src_len = 0; | |
170 | |||
171 |
2/2✓ Branch 0 taken 997 times.
✓ Branch 1 taken 12 times.
|
1009 | for (src_pos = srcL; *src_pos; src_pos++) |
172 | { | ||
173 | 997 | gint tmp; | |
174 | |||
175 | 997 | src = *src_pos; | |
176 | 997 | tmp = strlen (src); | |
177 |
1/2✓ Branch 0 taken 997 times.
✗ Branch 1 not taken.
|
997 | g_assert (tmp % 2 == 0); |
178 | 997 | src_len += tmp; | |
179 | } | ||
180 | |||
181 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | g_assert (src_len >= 2); |
182 | 12 | *len = src_len / 2; | |
183 | 12 | res = g_malloc0 (*len); | |
184 | 12 | dst = res; | |
185 | |||
186 |
2/2✓ Branch 1 taken 997 times.
✓ Branch 2 taken 12 times.
|
1021 | for (src_pos = srcL; *src_pos; src_pos++) |
187 |
2/2✓ Branch 0 taken 29062 times.
✓ Branch 1 taken 997 times.
|
30059 | for (src = *src_pos; *src; src += 2, dst += 1) |
188 |
4/4✓ Branch 0 taken 25170 times.
✓ Branch 1 taken 3892 times.
✓ Branch 2 taken 26564 times.
✓ Branch 3 taken 2498 times.
|
29062 | *dst = (guint8) ((HEX_TO_INT (src[0]) << 4) | (HEX_TO_INT (src[1]))); |
189 | |||
190 | 12 | return res; | |
191 | } | ||
192 | |||
193 | static guint8 * | ||
194 | 27 | vfs301_proto_generate (int type, int subtype, gssize *len) | |
195 | { | ||
196 |
4/5✓ Branch 0 taken 13 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
|
27 | switch (type) |
197 | { | ||
198 | 13 | case 0x01: | |
199 | case 0x04: | ||
200 | /* After cmd 0x04 is sent, a data is received on VALIDITY_RECEIVE_ENDPOINT_CTRL. | ||
201 | * If it is 0x0000: | ||
202 | * additional 64B and 224B are read from _DATA, then vfs301_next_scan_FA00 is | ||
203 | * sent, 0000 received from _CTRL, and then continue with wait loop | ||
204 | * If it is 0x1204: | ||
205 | * => reinit? | ||
206 | */ | ||
207 | case 0x17: | ||
208 | case 0x19: | ||
209 | case 0x1A: | ||
210 | { | ||
211 | 13 | guint8 *data = g_malloc0 (1); | |
212 | 13 | *data = type; | |
213 | 13 | *len = 1; | |
214 | 13 | return data; | |
215 | } | ||
216 | |||
217 | 2 | case 0x0B: | |
218 | 2 | return vfs301_proto_generate_0B (subtype, len); | |
219 | |||
220 | 7 | case 0x02D0: | |
221 | { | ||
222 | 7 | const char **dataLs[] = { | |
223 | vfs301_02D0_01, | ||
224 | vfs301_02D0_02, | ||
225 | vfs301_02D0_03, | ||
226 | vfs301_02D0_04, | ||
227 | vfs301_02D0_05, | ||
228 | vfs301_02D0_06, | ||
229 | vfs301_02D0_07, | ||
230 | }; | ||
231 |
1/2✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
|
7 | g_assert ((int) subtype <= G_N_ELEMENTS (dataLs)); |
232 | 7 | return translate_str (dataLs[subtype - 1], len); | |
233 | } | ||
234 | |||
235 | 5 | case 0x0220: | |
236 |
4/5✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
|
5 | switch (subtype) |
237 | { | ||
238 | 1 | case 1: | |
239 | 1 | return translate_str (vfs301_0220_01, len); | |
240 | |||
241 | 2 | case 2: | |
242 | 2 | return translate_str (vfs301_0220_02, len); | |
243 | |||
244 | 1 | case 3: | |
245 | 1 | return translate_str (vfs301_0220_03, len); | |
246 | |||
247 | 1 | case 0xFA00: | |
248 | case 0x2C01: | ||
249 | case 0x5E01: { | ||
250 | 1 | guint8 *data; | |
251 | 1 | guint8 *field; | |
252 | |||
253 | 1 | data = translate_str (vfs301_next_scan_template, len); | |
254 | 1 | field = data + *len - (sizeof (S4_TAIL) - 1) / 2 - 4; | |
255 | |||
256 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
1 | g_assert (field >= data && field < data + *len); |
257 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | g_assert (field[0] == 0xDE); |
258 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | g_assert (field[1] == 0xAD); |
259 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | g_assert (field[2] == 0xDE); |
260 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | g_assert (field[3] == 0xAD); |
261 | |||
262 | 1 | field[0] = (guint8) ((subtype >> 8) & 0xFF); | |
263 | 1 | field[1] = (guint8) (subtype & 0xFF); | |
264 | 1 | field[2] = field[0]; | |
265 | 1 | field[3] = field[1]; | |
266 | |||
267 | 1 | return data; | |
268 | } | ||
269 | |||
270 | ✗ | default: | |
271 | ✗ | g_assert_not_reached (); | |
272 | break; | ||
273 | } | ||
274 | break; | ||
275 | |||
276 | case 0x06: | ||
277 | default: | ||
278 | ✗ | break; | |
279 | } | ||
280 | |||
281 | ✗ | g_assert_not_reached (); | |
282 | *len = 0; | ||
283 | return NULL; | ||
284 | } | ||
285 | |||
286 | /************************** SCAN IMAGE PROCESSING *****************************/ | ||
287 | |||
288 | #ifdef SCAN_FINISH_DETECTION | ||
289 | static int | ||
290 | img_is_finished_scan (fp_line_t *lines, int no_lines) | ||
291 | { | ||
292 | int i; | ||
293 | int j; | ||
294 | int rv = 1; | ||
295 | |||
296 | for (i = no_lines - VFS301_FP_SUM_LINES; i < no_lines; i++) | ||
297 | { | ||
298 | /* check the line for fingerprint data */ | ||
299 | for (j = 0; j < sizeof (lines[i].sum2); j++) | ||
300 | if (lines[i].sum2[j] > (VFS301_FP_SUM_MEDIAN + VFS301_FP_SUM_EMPTY_RANGE)) | ||
301 | rv = 0; | ||
302 | } | ||
303 | |||
304 | return rv; | ||
305 | } | ||
306 | #endif | ||
307 | |||
308 | static int | ||
309 | 874 | scanline_diff (const guint8 *scanlines, int prev, int cur) | |
310 | { | ||
311 | 874 | const guint8 *line1 = scanlines + prev * VFS301_FP_OUTPUT_WIDTH; | |
312 | 874 | const guint8 *line2 = scanlines + cur * VFS301_FP_OUTPUT_WIDTH; | |
313 | 874 | int i; | |
314 | 874 | int diff; | |
315 | |||
316 | #ifdef OUTPUT_RAW | ||
317 | /* We only need the image, not the surrounding stuff. */ | ||
318 | line1 = ((vfs301_line_t *) line1)->scan; | ||
319 | line2 = ((vfs301_line_t *) line2)->scan; | ||
320 | #endif | ||
321 | |||
322 | /* TODO: This doesn't work too well when there are parallel lines in the | ||
323 | * fingerprint. */ | ||
324 |
2/2✓ Branch 0 taken 174800 times.
✓ Branch 1 taken 874 times.
|
175674 | for (diff = 0, i = 0; i < VFS301_FP_WIDTH; i++) |
325 | { | ||
326 |
2/2✓ Branch 0 taken 80521 times.
✓ Branch 1 taken 94279 times.
|
174800 | if (*line1 > *line2) |
327 | 80521 | diff += *line1 - *line2; | |
328 | else | ||
329 | 94279 | diff += *line2 - *line1; | |
330 | |||
331 | 174800 | line1++; | |
332 | 174800 | line2++; | |
333 | } | ||
334 | |||
335 | 874 | return (diff / VFS301_FP_WIDTH) > VFS301_FP_LINE_DIFF_THRESHOLD; | |
336 | } | ||
337 | |||
338 | /** Transform the input data to a normalized fingerprint scan */ | ||
339 | void | ||
340 | 1 | vfs301_extract_image (FpDeviceVfs301 *vfs, guint8 *output, int *output_height | |
341 | ) | ||
342 | { | ||
343 | 1 | const guint8 *scanlines = vfs->scanline_buf; | |
344 | 1 | int last_line; | |
345 | 1 | int i; | |
346 | |||
347 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | g_assert (vfs->scanline_count >= 1); |
348 | |||
349 | 1 | *output_height = 1; | |
350 | 1 | memcpy (output, scanlines, VFS301_FP_OUTPUT_WIDTH); | |
351 | 1 | last_line = 0; | |
352 | |||
353 | /* The following algorithm is quite trivial - it just picks lines that | ||
354 | * differ more than VFS301_FP_LINE_DIFF_THRESHOLD. | ||
355 | * TODO: A nicer approach would be to pick those lines and then do some kind | ||
356 | * of bi/tri-linear resampling to get the output (so that we don't get so | ||
357 | * many false edges etc.). | ||
358 | */ | ||
359 |
2/2✓ Branch 0 taken 874 times.
✓ Branch 1 taken 1 times.
|
875 | for (i = 1; i < vfs->scanline_count; i++) |
360 | { | ||
361 |
2/2✓ Branch 0 taken 213 times.
✓ Branch 1 taken 661 times.
|
874 | if (scanline_diff (scanlines, last_line, i)) |
362 | { | ||
363 | 213 | memcpy ( | |
364 | 213 | output + VFS301_FP_OUTPUT_WIDTH * (*output_height), | |
365 | 213 | scanlines + VFS301_FP_OUTPUT_WIDTH * i, | |
366 | VFS301_FP_OUTPUT_WIDTH | ||
367 | ); | ||
368 | 213 | last_line = i; | |
369 | 213 | (*output_height)++; | |
370 | } | ||
371 | } | ||
372 | 1 | } | |
373 | |||
374 | static int | ||
375 | 3 | img_process_data (int first_block, FpDeviceVfs301 *dev, const guint8 *buf, int len) | |
376 | { | ||
377 | 3 | vfs301_line_t *lines = (vfs301_line_t *) buf; | |
378 | 3 | int no_lines = len / sizeof (vfs301_line_t); | |
379 | 3 | int i; | |
380 | /*int no_nonempty;*/ | ||
381 | 3 | guint8 *cur_line; | |
382 | 3 | int last_img_height; | |
383 | |||
384 | #ifdef SCAN_FINISH_DETECTION | ||
385 | int finished_scan; | ||
386 | #endif | ||
387 | |||
388 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
|
3 | if (first_block) |
389 | { | ||
390 | 1 | last_img_height = 0; | |
391 | 1 | dev->scanline_count = no_lines; | |
392 | } | ||
393 | else | ||
394 | { | ||
395 | 2 | last_img_height = dev->scanline_count; | |
396 | 2 | dev->scanline_count += no_lines; | |
397 | } | ||
398 | |||
399 | 3 | dev->scanline_buf = g_realloc (dev->scanline_buf, dev->scanline_count * VFS301_FP_OUTPUT_WIDTH); | |
400 | |||
401 | 3 | for (cur_line = dev->scanline_buf + last_img_height * VFS301_FP_OUTPUT_WIDTH, i = 0; | |
402 |
2/2✓ Branch 0 taken 875 times.
✓ Branch 1 taken 3 times.
|
878 | i < no_lines; |
403 | 875 | i++, cur_line += VFS301_FP_OUTPUT_WIDTH | |
404 | ) | ||
405 | { | ||
406 | #ifndef OUTPUT_RAW | ||
407 | 875 | memcpy (cur_line, lines[i].scan, VFS301_FP_OUTPUT_WIDTH); | |
408 | #else | ||
409 | memcpy (cur_line, &lines[i], VFS301_FP_OUTPUT_WIDTH); | ||
410 | #endif | ||
411 | } | ||
412 | |||
413 | #ifdef SCAN_FINISH_DETECTION | ||
414 | finished_scan = img_is_finished_scan (lines, no_lines); | ||
415 | |||
416 | return !finished_scan; | ||
417 | #else /* SCAN_FINISH_DETECTION */ | ||
418 | 3 | return 1; /* Just continue until data is coming */ | |
419 | #endif | ||
420 | } | ||
421 | |||
422 | /************************** PROTOCOL STUFF ************************************/ | ||
423 | |||
424 | #define USB_RECV(from, len) \ | ||
425 | usb_recv (dev, from, len, NULL, NULL) | ||
426 | |||
427 | #define USB_SEND(type, subtype) \ | ||
428 | { \ | ||
429 | const guint8 *data; \ | ||
430 | gssize len; \ | ||
431 | data = vfs301_proto_generate (type, subtype, &len); \ | ||
432 | usb_send (dev, data, len, NULL); \ | ||
433 | } | ||
434 | |||
435 | #define RAW_DATA(x) g_memdup2 (x, sizeof (x)), sizeof (x) | ||
436 | |||
437 | #define IS_VFS301_FP_SEQ_START(b) ((b[0] == 0x01) && (b[1] == 0xfe)) | ||
438 | |||
439 | static int | ||
440 | 3 | vfs301_proto_process_data (FpDeviceVfs301 *dev, int first_block, const guint8 *buf, gint len) | |
441 | { | ||
442 | 3 | int i; | |
443 | |||
444 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
|
3 | if (first_block) |
445 | { | ||
446 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | g_assert (len >= VFS301_FP_FRAME_SIZE); |
447 | |||
448 | /* Skip bytes until start_sequence is found */ | ||
449 |
1/2✓ Branch 0 taken 225 times.
✗ Branch 1 not taken.
|
225 | for (i = 0; i < VFS301_FP_FRAME_SIZE; i++, buf++, len--) |
450 |
4/4✓ Branch 0 taken 3 times.
✓ Branch 1 taken 222 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1 times.
|
225 | if (IS_VFS301_FP_SEQ_START (buf)) |
451 | break; | ||
452 | } | ||
453 | |||
454 | 3 | return img_process_data (first_block, dev, buf, len); | |
455 | } | ||
456 | |||
457 | void | ||
458 | 1 | vfs301_proto_request_fingerprint (FpDeviceVfs301 *dev) | |
459 | { | ||
460 | 1 | USB_SEND (0x0220, 0xFA00); | |
461 | 1 | USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 000000000000 */ | |
462 | 1 | } | |
463 | |||
464 | int | ||
465 | 2 | vfs301_proto_peek_event (FpDeviceVfs301 *dev) | |
466 | { | ||
467 | 4 | g_autoptr(GError) error = NULL; | |
468 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | g_autoptr(FpiUsbTransfer) transfer = NULL; |
469 | |||
470 | 2 | const char no_event[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; | |
471 | 2 | const char got_event[] = {0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00}; | |
472 | |||
473 | 2 | USB_SEND (0x17, -1); | |
474 | 2 | usb_recv (dev, VFS301_RECEIVE_ENDPOINT_CTRL, 7, &transfer, &error); | |
475 | |||
476 | /* XXX: This is obviously not a sane error handling! */ | ||
477 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | g_assert (!error); |
478 | |||
479 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if (memcmp (transfer->buffer, no_event, sizeof (no_event)) == 0) |
480 | return 0; | ||
481 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | else if (memcmp (transfer->buffer, got_event, sizeof (no_event)) == 0) |
482 | return 1; | ||
483 | else | ||
484 | 2 | g_assert_not_reached (); | |
485 | } | ||
486 | |||
487 | /* XXX: We sometimes need to receive data on from two endpoints at the same | ||
488 | * time. However, as this driver is currently all synchronous (yikes), | ||
489 | * we will run into timeouts randomly and need to then try again. | ||
490 | */ | ||
491 | #define PARALLEL_RECEIVE(e1, l1, e2, l2) \ | ||
492 | { \ | ||
493 | g_autoptr(GError) error = NULL; \ | ||
494 | usb_recv (dev, e1, l1, NULL, &error); \ | ||
495 | usb_recv (dev, e2, l2, NULL, NULL); \ | ||
496 | if (g_error_matches (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_TIMED_OUT)) \ | ||
497 | usb_recv (dev, e1, l1, NULL, NULL); \ | ||
498 | } | ||
499 | |||
500 | static void | ||
501 | 4 | vfs301_proto_process_event_cb (FpiUsbTransfer *transfer, | |
502 | FpDevice *device, | ||
503 | gpointer user_data, GError *error) | ||
504 | { | ||
505 | 4 | FpDeviceVfs301 *self = FPI_DEVICE_VFS301 (device); | |
506 | |||
507 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (error) |
508 | { | ||
509 | ✗ | g_warning ("Error receiving data: %s", error->message); | |
510 | ✗ | g_error_free (error); | |
511 | ✗ | self->recv_progress = VFS301_FAILURE; | |
512 | ✗ | return; | |
513 | } | ||
514 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
|
4 | else if (transfer->actual_length < transfer->length) |
515 | { | ||
516 | /* TODO: process the data anyway? */ | ||
517 | 1 | self->recv_progress = VFS301_ENDED; | |
518 | 1 | return; | |
519 | } | ||
520 | else | ||
521 | { | ||
522 | 3 | FpiUsbTransfer *new; | |
523 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (!vfs301_proto_process_data (self, |
524 | transfer->length == VFS301_FP_RECV_LEN_1, | ||
525 | 3 | transfer->buffer, | |
526 | transfer->actual_length)) | ||
527 | { | ||
528 | ✗ | self->recv_progress = VFS301_ENDED; | |
529 | ✗ | return; | |
530 | } | ||
531 | |||
532 | 3 | new = fpi_usb_transfer_new (device); | |
533 | |||
534 | 3 | fpi_usb_transfer_fill_bulk (new, VFS301_RECEIVE_ENDPOINT_DATA, VFS301_FP_RECV_LEN_2); | |
535 | 3 | fpi_usb_transfer_submit (new, VFS301_FP_RECV_TIMEOUT, NULL, | |
536 | vfs301_proto_process_event_cb, NULL); | ||
537 | 3 | return; | |
538 | } | ||
539 | } | ||
540 | |||
541 | void | ||
542 | 1 | vfs301_proto_process_event_start (FpDeviceVfs301 *dev) | |
543 | { | ||
544 | 1 | FpiUsbTransfer *transfer; | |
545 | |||
546 | /* | ||
547 | * Notes: | ||
548 | * | ||
549 | * seen next_scan order: | ||
550 | * o FA00 | ||
551 | * o FA00 | ||
552 | * o 2C01 | ||
553 | * o FA00 | ||
554 | * o FA00 | ||
555 | * o 2C01 | ||
556 | * o FA00 | ||
557 | * o FA00 | ||
558 | * o 2C01 | ||
559 | * o 5E01 !? | ||
560 | * o FA00 | ||
561 | * o FA00 | ||
562 | * o 2C01 | ||
563 | * o FA00 | ||
564 | * o FA00 | ||
565 | * o 2C01 | ||
566 | */ | ||
567 | 1 | USB_RECV (VFS301_RECEIVE_ENDPOINT_DATA, 64); | |
568 | |||
569 | /* now read the fingerprint data, while there are some */ | ||
570 | 1 | transfer = fpi_usb_transfer_new (FP_DEVICE (dev)); | |
571 | 1 | dev->recv_progress = VFS301_ONGOING; | |
572 | |||
573 | 1 | fpi_usb_transfer_fill_bulk (transfer, VFS301_RECEIVE_ENDPOINT_DATA, VFS301_FP_RECV_LEN_1); | |
574 | 1 | fpi_usb_transfer_submit (transfer, VFS301_FP_RECV_TIMEOUT, NULL, | |
575 | vfs301_proto_process_event_cb, NULL); | ||
576 | 1 | } | |
577 | |||
578 | int | ||
579 | 1 | vfs301_proto_process_event_poll (FpDeviceVfs301 *dev) | |
580 | { | ||
581 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (dev->recv_progress != VFS301_ENDED) |
582 | return dev->recv_progress; | ||
583 | |||
584 | /* Finish the scan process... */ | ||
585 | |||
586 | 1 | USB_SEND (0x04, -1); | |
587 | /* the following may come in random order, data may not come at all, don't | ||
588 | * try for too long... */ | ||
589 |
1/2✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
|
1 | PARALLEL_RECEIVE ( |
590 | VFS301_RECEIVE_ENDPOINT_CTRL, 2, /* 1204 */ | ||
591 | VFS301_RECEIVE_ENDPOINT_DATA, 16384 | ||
592 | 1 | ); | |
593 | |||
594 | 1 | USB_SEND (0x0220, 2); | |
595 |
1/2✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
|
1 | PARALLEL_RECEIVE ( |
596 | VFS301_RECEIVE_ENDPOINT_DATA, 5760, /* seems to always come */ | ||
597 | VFS301_RECEIVE_ENDPOINT_CTRL, 2 /* 0000 */ | ||
598 | 1 | ); | |
599 | |||
600 | 1 | return dev->recv_progress; | |
601 | } | ||
602 | |||
603 | void | ||
604 | 1 | vfs301_proto_init (FpDeviceVfs301 *dev) | |
605 | { | ||
606 | 1 | USB_SEND (0x01, -1); | |
607 | 1 | USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 38); | |
608 | 1 | USB_SEND (0x0B, 0x04); | |
609 | 1 | USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 6); /* 000000000000 */ | |
610 | 1 | USB_SEND (0x0B, 0x05); | |
611 | 1 | USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 7); /* 00000000000000 */ | |
612 | 1 | USB_SEND (0x19, -1); | |
613 | 1 | USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 64); | |
614 | 1 | USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 4); /* 6BB4D0BC */ | |
615 | 1 | usb_send (dev, RAW_DATA (vfs301_06_1), NULL); | |
616 | 1 | USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ | |
617 | |||
618 | 1 | USB_SEND (0x01, -1); | |
619 | 1 | USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 38); | |
620 | 1 | USB_SEND (0x1A, -1); | |
621 | 1 | USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ | |
622 | 1 | usb_send (dev, RAW_DATA (vfs301_06_2), NULL); | |
623 | 1 | USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ | |
624 | 1 | USB_SEND (0x0220, 1); | |
625 | 1 | USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ | |
626 | 1 | USB_RECV (VFS301_RECEIVE_ENDPOINT_DATA, 256); | |
627 | 1 | USB_RECV (VFS301_RECEIVE_ENDPOINT_DATA, 32); | |
628 | |||
629 | 1 | USB_SEND (0x1A, -1); | |
630 | 1 | USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ | |
631 | 1 | usb_send (dev, RAW_DATA (vfs301_06_3), NULL); | |
632 | 1 | USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ | |
633 | |||
634 | 1 | USB_SEND (0x01, -1); | |
635 | 1 | USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 38); | |
636 | 1 | USB_SEND (0x02D0, 1); | |
637 | 1 | USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ | |
638 | 1 | USB_RECV (VFS301_RECEIVE_ENDPOINT_DATA, 11648); /* 56 * vfs301_init_line_t[] */ | |
639 | 1 | USB_SEND (0x02D0, 2); | |
640 | 1 | USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ | |
641 | 1 | USB_RECV (VFS301_RECEIVE_ENDPOINT_DATA, 53248); /* 2 * 128 * vfs301_init_line_t[] */ | |
642 | 1 | USB_SEND (0x02D0, 3); | |
643 | 1 | USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ | |
644 | 1 | USB_RECV (VFS301_RECEIVE_ENDPOINT_DATA, 19968); /* 96 * vfs301_init_line_t[] */ | |
645 | 1 | USB_SEND (0x02D0, 4); | |
646 | 1 | USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ | |
647 | 1 | USB_RECV (VFS301_RECEIVE_ENDPOINT_DATA, 5824); /* 28 * vfs301_init_line_t[] */ | |
648 | 1 | USB_SEND (0x02D0, 5); | |
649 | 1 | USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ | |
650 | 1 | USB_RECV (VFS301_RECEIVE_ENDPOINT_DATA, 6656); /* 32 * vfs301_init_line_t[] */ | |
651 | 1 | USB_SEND (0x02D0, 6); | |
652 | 1 | USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ | |
653 | 1 | USB_RECV (VFS301_RECEIVE_ENDPOINT_DATA, 6656); /* 32 * vfs301_init_line_t[] */ | |
654 | 1 | USB_SEND (0x02D0, 7); | |
655 | 1 | USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ | |
656 | 1 | USB_RECV (VFS301_RECEIVE_ENDPOINT_DATA, 832); | |
657 | 1 | usb_send (dev, RAW_DATA (vfs301_12), NULL); | |
658 | 1 | USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ | |
659 | |||
660 | 1 | USB_SEND (0x1A, -1); | |
661 | 1 | USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ | |
662 | 1 | usb_send (dev, RAW_DATA (vfs301_06_2), NULL); | |
663 | 1 | USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ | |
664 | 1 | USB_SEND (0x0220, 2); | |
665 |
1/2✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
|
1 | PARALLEL_RECEIVE ( |
666 | VFS301_RECEIVE_ENDPOINT_CTRL, 2, /* 0000 */ | ||
667 | VFS301_RECEIVE_ENDPOINT_DATA, 5760 | ||
668 | 1 | ); | |
669 | |||
670 | 1 | USB_SEND (0x1A, -1); | |
671 | 1 | USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ | |
672 | 1 | usb_send (dev, RAW_DATA (vfs301_06_1), NULL); | |
673 | 1 | USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ | |
674 | |||
675 | 1 | USB_SEND (0x1A, -1); | |
676 | 1 | USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ | |
677 | 1 | usb_send (dev, RAW_DATA (vfs301_06_4), NULL); | |
678 | 1 | USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ | |
679 | 1 | usb_send (dev, RAW_DATA (vfs301_24), NULL); /* turns on white */ | |
680 | 1 | USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2); /* 0000 */ | |
681 | |||
682 | 1 | USB_SEND (0x01, -1); | |
683 | 1 | USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 38); | |
684 | 1 | USB_SEND (0x0220, 3); | |
685 | 1 | USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 2368); | |
686 | 1 | USB_RECV (VFS301_RECEIVE_ENDPOINT_CTRL, 36); | |
687 | 1 | USB_RECV (VFS301_RECEIVE_ENDPOINT_DATA, 5760); | |
688 | 1 | } | |
689 | |||
690 | void | ||
691 | 1 | vfs301_proto_deinit (FpDeviceVfs301 *dev) | |
692 | { | ||
693 | 1 | } | |
694 |