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