GCC Code Coverage Report


Directory: ./
File: libfprint/drivers/vfs5011.c
Date: 2024-09-16 14:36:32
Exec Total Coverage
Lines: 273 311 87.8%
Functions: 24 24 100.0%
Branches: 56 92 60.9%

Line Branch Exec Source
1 /*
2 * Validity Sensors, Inc. VFS5011 Fingerprint Reader driver for libfprint
3 * Copyright (C) 2013 Arseniy Lartsev <arseniy@chalmers.se>
4 * AceLan Kao <acelan.kao@canonical.com>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #define FP_COMPONENT "vfs5011"
22
23 #include "drivers_api.h"
24 #include "vfs5011_proto.h"
25
26 /* =================== sync/async USB transfer sequence ==================== */
27
28 enum {
29 ACTION_SEND,
30 ACTION_RECEIVE,
31 };
32
33 struct usb_action
34 {
35 int type;
36 const char *name;
37 int endpoint;
38 int size;
39 unsigned char *data;
40 int correct_reply_size;
41 };
42
43 #define SEND(ENDPOINT, COMMAND) \
44 { \
45 .type = ACTION_SEND, \
46 .endpoint = ENDPOINT, \
47 .name = #COMMAND, \
48 .size = sizeof (COMMAND), \
49 .data = COMMAND \
50 },
51
52 #define RECV(ENDPOINT, SIZE) \
53 { \
54 .type = ACTION_RECEIVE, \
55 .endpoint = ENDPOINT, \
56 .size = SIZE, \
57 .data = NULL \
58 },
59
60 #define RECV_CHECK(ENDPOINT, SIZE, EXPECTED) \
61 { \
62 .type = ACTION_RECEIVE, \
63 .endpoint = ENDPOINT, \
64 .size = SIZE, \
65 .data = EXPECTED, \
66 .correct_reply_size = sizeof (EXPECTED) \
67 },
68
69 struct usbexchange_data
70 {
71 int stepcount;
72 FpImageDevice *device;
73 struct usb_action *actions;
74 void *receive_buf;
75 int timeout;
76 };
77
78 static void start_scan (FpImageDevice *dev);
79
80 static void
81 47 async_send_cb (FpiUsbTransfer *transfer, FpDevice *device,
82 gpointer user_data, GError *error)
83 {
84 47 struct usbexchange_data *data = fpi_ssm_get_data (transfer->ssm);
85 47 struct usb_action *action;
86
87
1/2
✓ Branch 1 taken 47 times.
✗ Branch 2 not taken.
47 g_assert (!(fpi_ssm_get_cur_state (transfer->ssm) >= data->stepcount));
88
89 47 action = &data->actions[fpi_ssm_get_cur_state (transfer->ssm)];
90
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 47 times.
47 g_assert (!(action->type != ACTION_SEND));
91
92
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 47 times.
47 if (error)
93 {
94 /* Transfer not completed, return IO error */
95 fpi_ssm_mark_failed (transfer->ssm, error);
96 return;
97 }
98
99 /* success */
100 47 fpi_ssm_next_state (transfer->ssm);
101 }
102
103 static void
104 70 async_recv_cb (FpiUsbTransfer *transfer, FpDevice *device,
105 gpointer user_data, GError *error)
106 {
107 70 struct usbexchange_data *data = fpi_ssm_get_data (transfer->ssm);
108 70 struct usb_action *action;
109
110
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 70 times.
70 if (error)
111 {
112 /* Transfer not completed, return IO error */
113 fpi_ssm_mark_failed (transfer->ssm, error);
114 return;
115 }
116
117
1/2
✓ Branch 1 taken 70 times.
✗ Branch 2 not taken.
70 g_assert (!(fpi_ssm_get_cur_state (transfer->ssm) >= data->stepcount));
118
119 70 action = &data->actions[fpi_ssm_get_cur_state (transfer->ssm)];
120
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 70 times.
70 g_assert (!(action->type != ACTION_RECEIVE));
121
122
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 33 times.
70 if (action->data != NULL)
123 {
124
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
37 if (transfer->actual_length != action->correct_reply_size)
125 {
126 fp_err ("Got %d bytes instead of %d",
127 (gint) transfer->actual_length,
128 action->correct_reply_size);
129 fpi_ssm_mark_failed (transfer->ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
130 return;
131 }
132
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
37 if (memcmp (transfer->buffer, action->data,
133 action->correct_reply_size) != 0)
134 {
135 fp_dbg ("Wrong reply:");
136 fpi_ssm_mark_failed (transfer->ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
137 return;
138 }
139 }
140 else
141 {
142 33 fp_dbg ("Got %d bytes out of %d",
143 (gint) transfer->actual_length,
144 (gint) transfer->length);
145 }
146
147 70 fpi_ssm_next_state (transfer->ssm);
148 }
149
150 static void
151 117 usbexchange_loop (FpiSsm *ssm, FpDevice *_dev)
152 {
153 117 struct usbexchange_data *data = fpi_ssm_get_data (ssm);
154 117 struct usb_action *action = &data->actions[fpi_ssm_get_cur_state (ssm)];
155 117 FpiUsbTransfer *transfer;
156
157
1/2
✓ Branch 1 taken 117 times.
✗ Branch 2 not taken.
117 g_assert (fpi_ssm_get_cur_state (ssm) < data->stepcount);
158
159
2/3
✓ Branch 0 taken 47 times.
✓ Branch 1 taken 70 times.
✗ Branch 2 not taken.
117 switch (action->type)
160 {
161 47 case ACTION_SEND:
162 47 fp_dbg ("Sending %s", action->name);
163 47 transfer = fpi_usb_transfer_new (_dev);
164 47 fpi_usb_transfer_fill_bulk_full (transfer, action->endpoint,
165 47 action->data, action->size,
166 NULL);
167 47 transfer->ssm = ssm;
168 47 transfer->short_is_error = TRUE;
169 47 fpi_usb_transfer_submit (transfer, data->timeout, NULL,
170 async_send_cb, NULL);
171 47 break;
172
173 70 case ACTION_RECEIVE:
174 70 fp_dbg ("Receiving %d bytes", action->size);
175 70 transfer = fpi_usb_transfer_new (_dev);
176 70 fpi_usb_transfer_fill_bulk_full (transfer, action->endpoint,
177 70 data->receive_buf,
178 70 action->size, NULL);
179 70 transfer->ssm = ssm;
180 70 fpi_usb_transfer_submit (transfer, data->timeout, NULL,
181 async_recv_cb, NULL);
182 70 break;
183
184 default:
185 fp_err ("Bug detected: invalid action %d", action->type);
186 fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
187 return;
188 }
189 }
190
191 static void
192 3 usb_exchange_async (FpiSsm *ssm,
193 struct usbexchange_data *data,
194 const char *exchange_name)
195 {
196 3 FpiSsm *subsm = fpi_ssm_new_full (FP_DEVICE (data->device),
197 usbexchange_loop,
198 data->stepcount,
199 data->stepcount,
200 exchange_name);
201
202 3 fpi_ssm_set_data (subsm, data, NULL);
203 3 fpi_ssm_start_subsm (ssm, subsm);
204 3 }
205
206 /* ====================== utils ======================= */
207
208 /* Calculade squared standand deviation of sum of two lines */
209 static int
210 3870 vfs5011_get_deviation2 (struct fpi_line_asmbl_ctx *ctx, GSList *row1, GSList *row2)
211 {
212 3870 unsigned char *buf1, *buf2;
213 3870 int res = 0, mean = 0, i;
214 3870 const int size = 64;
215
216 3870 buf1 = (unsigned char *) row1->data + 56;
217 3870 buf2 = (unsigned char *) row2->data + 168;
218
219
2/2
✓ Branch 0 taken 247680 times.
✓ Branch 1 taken 3870 times.
251550 for (i = 0; i < size; i++)
220 247680 mean += (int) buf1[i] + (int) buf2[i];
221
222 3870 mean /= size;
223
224
2/2
✓ Branch 0 taken 247680 times.
✓ Branch 1 taken 3870 times.
251550 for (i = 0; i < size; i++)
225 {
226 247680 int dev = (int) buf1[i] + (int) buf2[i] - mean;
227 247680 res += dev * dev;
228 }
229
230 3870 return res / size;
231 }
232
233 static unsigned char
234 106880 vfs5011_get_pixel (struct fpi_line_asmbl_ctx *ctx,
235 GSList *row,
236 unsigned x)
237 {
238 106880 unsigned char *data = (unsigned char *) row->data + 8;
239
240 106880 return data[x];
241 }
242
243 /* ====================== main stuff ======================= */
244
245 enum {
246 CAPTURE_LINES = 256,
247 MAXLINES = 2000,
248 MAX_CAPTURE_LINES = 100000,
249 };
250
251 static struct fpi_line_asmbl_ctx assembling_ctx = {
252 .line_width = VFS5011_IMAGE_WIDTH,
253 .max_height = MAXLINES,
254 .resolution = 10,
255 .median_filter_size = 25,
256 .max_search_offset = 30,
257 .get_deviation = vfs5011_get_deviation2,
258 .get_pixel = vfs5011_get_pixel,
259 };
260
261 struct _FpDeviceVfs5011
262 {
263 FpImageDevice parent;
264
265 unsigned char *total_buffer;
266 unsigned char *capture_buffer;
267 unsigned char *row_buffer;
268 unsigned char *lastline;
269 GSList *rows;
270 int lines_captured, lines_recorded, empty_lines;
271 int max_lines_captured, max_lines_recorded;
272 int lines_total, lines_total_allocated;
273 gboolean loop_running;
274 gboolean deactivating;
275 struct usbexchange_data init_sequence;
276 };
277
278 G_DECLARE_FINAL_TYPE (FpDeviceVfs5011, fpi_device_vfs5011, FPI, DEVICE_VFS5011,
279 FpImageDevice);
280
4/5
✓ Branch 0 taken 120 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 120 times.
✓ Branch 3 taken 120 times.
✗ Branch 4 not taken.
768 G_DEFINE_TYPE (FpDeviceVfs5011, fpi_device_vfs5011, FP_TYPE_IMAGE_DEVICE);
281
282 enum {
283 DEV_ACTIVATE_REQUEST_FPRINT,
284 DEV_ACTIVATE_INIT_COMPLETE,
285 DEV_ACTIVATE_READ_DATA,
286 DEV_ACTIVATE_DATA_COMPLETE,
287 DEV_ACTIVATE_PREPARE_NEXT_CAPTURE,
288 DEV_ACTIVATE_NUM_STATES
289 };
290
291 enum {
292 DEV_OPEN_START,
293 DEV_OPEN_NUM_STATES
294 };
295
296 static void
297 1 capture_init (FpDeviceVfs5011 *self, int max_captured,
298 int max_recorded)
299 {
300 1 fp_dbg ("capture_init");
301 1 self->lastline = NULL;
302 1 self->lines_captured = 0;
303 1 self->lines_recorded = 0;
304 1 self->empty_lines = 0;
305 1 self->lines_total = 0;
306 1 self->lines_total_allocated = 0;
307 1 self->total_buffer = NULL;
308 1 self->max_lines_captured = max_captured;
309 1 self->max_lines_recorded = max_recorded;
310 1 }
311
312 static int
313 9 process_chunk (FpDeviceVfs5011 *self, int transferred)
314 {
315 9 enum {
316 DEVIATION_THRESHOLD = 15 * 15,
317 DIFFERENCE_THRESHOLD = 600,
318 STOP_CHECK_LINES = 50
319 };
320
321 9 fp_dbg ("process_chunk: got %d bytes", transferred);
322 9 int lines_captured = transferred / VFS5011_LINE_SIZE;
323 9 int i;
324
325
2/2
✓ Branch 0 taken 2060 times.
✓ Branch 1 taken 8 times.
2068 for (i = 0; i < lines_captured; i++)
326 {
327 2060 unsigned char *linebuf = self->capture_buffer
328 2060 + i * VFS5011_LINE_SIZE;
329
330
2/2
✓ Branch 1 taken 50 times.
✓ Branch 2 taken 2010 times.
2060 if (fpi_std_sq_dev (linebuf + 8, VFS5011_IMAGE_WIDTH)
331 < DEVIATION_THRESHOLD)
332 {
333
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
50 if (self->lines_captured == 0)
334 continue;
335 else
336 50 self->empty_lines++;
337 }
338 else
339 {
340 2010 self->empty_lines = 0;
341 }
342
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2059 times.
2060 if (self->empty_lines >= STOP_CHECK_LINES)
343 {
344 1 fp_dbg ("process_chunk: got %d empty lines, finishing",
345 self->empty_lines);
346 1 return 1;
347 }
348
349 2059 self->lines_captured++;
350
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2059 times.
2059 if (self->lines_captured > self->max_lines_captured)
351 {
352 fp_dbg ("process_chunk: captured %d lines, finishing",
353 self->lines_captured);
354 return 1;
355 }
356
357
4/4
✓ Branch 0 taken 2058 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 272 times.
✓ Branch 3 taken 1786 times.
4117 if ((self->lastline == NULL) ||
358 2058 (fpi_mean_sq_diff_norm (self->lastline + 8,
359 linebuf + 8,
360 VFS5011_IMAGE_WIDTH) >= DIFFERENCE_THRESHOLD))
361 {
362 273 self->lastline = g_malloc (VFS5011_LINE_SIZE);
363 273 self->rows = g_slist_prepend (self->rows,
364 self->lastline);
365 273 memmove (self->lastline, linebuf, VFS5011_LINE_SIZE);
366 273 self->lines_recorded++;
367
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 273 times.
273 if (self->lines_recorded >= self->max_lines_recorded)
368 {
369 fp_dbg ("process_chunk: recorded %d lines, finishing",
370 self->lines_recorded);
371 return 1;
372 }
373 }
374 }
375 return 0;
376 }
377
378 static void
379 1 submit_image (FpiSsm *ssm,
380 FpDeviceVfs5011 *self,
381 FpImageDevice *dev)
382 {
383 1 FpImage *img;
384
385
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (self->lines_recorded < VFS5011_IMAGE_WIDTH)
386 {
387 fpi_image_device_retry_scan (dev, FP_DEVICE_RETRY_TOO_SHORT);
388 return;
389 }
390
391
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 g_assert (self->rows != NULL);
392
393 1 self->rows = g_slist_reverse (self->rows);
394
395 2 img = fpi_assemble_lines (&assembling_ctx, self->rows,
396 1 self->lines_recorded);
397
398 1 g_slist_free_full (self->rows, g_free);
399 1 self->rows = NULL;
400
401 1 fp_dbg ("Image captured, committing");
402
403 1 fpi_image_device_image_captured (dev, img);
404 }
405
406 static void
407 9 chunk_capture_callback (FpiUsbTransfer *transfer, FpDevice *device,
408 gpointer user_data, GError *error)
409 {
410 9 FpImageDevice *dev = FP_IMAGE_DEVICE (device);
411 9 FpDeviceVfs5011 *self;
412
413 9 self = FPI_DEVICE_VFS5011 (dev);
414
415
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
9 if (!error ||
416 g_error_matches (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_TIMED_OUT))
417 {
418 if (error)
419 g_error_free (error);
420
421
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 if (transfer->actual_length > 0)
422 9 fpi_image_device_report_finger_status (dev, TRUE);
423
424
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 8 times.
9 if (process_chunk (self, transfer->actual_length))
425 1 fpi_ssm_jump_to_state (transfer->ssm,
426 DEV_ACTIVATE_DATA_COMPLETE);
427 else
428 8 fpi_ssm_jump_to_state (transfer->ssm,
429 DEV_ACTIVATE_READ_DATA);
430 }
431 else
432 {
433 if (!self->deactivating)
434 {
435 fp_err ("Failed to capture data");
436 fpi_ssm_mark_failed (transfer->ssm, error);
437 }
438 else
439 {
440 g_error_free (error);
441 fpi_ssm_mark_completed (transfer->ssm);
442 }
443 }
444 9 }
445
446 static void
447 9 capture_chunk_async (FpDeviceVfs5011 *self,
448 GUsbDevice *handle, int nline,
449 int timeout, FpiSsm *ssm)
450 {
451 9 FpiUsbTransfer *transfer;
452
453 9 fp_dbg ("capture_chunk_async: capture %d lines, already have %d",
454 nline, self->lines_recorded);
455 9 enum {
456 DEVIATION_THRESHOLD = 15 * 15,
457 DIFFERENCE_THRESHOLD = 600,
458 STOP_CHECK_LINES = 50
459 };
460
461 9 transfer = fpi_usb_transfer_new (FP_DEVICE (self));
462 9 fpi_usb_transfer_fill_bulk_full (transfer,
463 VFS5011_IN_ENDPOINT_DATA,
464 9 self->capture_buffer,
465 9 nline * VFS5011_LINE_SIZE, NULL);
466 9 transfer->ssm = ssm;
467 9 fpi_usb_transfer_submit (transfer, timeout, fpi_device_get_cancellable (FP_DEVICE (self)),
468 chunk_capture_callback, NULL);
469 9 }
470
471 /*
472 * Device initialization. Windows driver only does it when the device is
473 * plugged in, but it doesn't harm to do this every time before scanning the
474 * image.
475 */
476 struct usb_action vfs5011_initialization[] = {
477 SEND (VFS5011_OUT_ENDPOINT, vfs5011_cmd_01)
478 RECV (VFS5011_IN_ENDPOINT_CTRL, 64)
479
480 SEND (VFS5011_OUT_ENDPOINT, vfs5011_cmd_19)
481 RECV (VFS5011_IN_ENDPOINT_CTRL, 64)
482 RECV (VFS5011_IN_ENDPOINT_CTRL, 64) /* B5C457F9 */
483
484 SEND (VFS5011_OUT_ENDPOINT, vfs5011_init_00)
485 RECV (VFS5011_IN_ENDPOINT_CTRL, 64) /* 0000FFFFFFFF */
486
487 SEND (VFS5011_OUT_ENDPOINT, vfs5011_init_01)
488 RECV (VFS5011_IN_ENDPOINT_CTRL, 64) /* 0000FFFFFFFFFF */
489
490 SEND (VFS5011_OUT_ENDPOINT, vfs5011_init_02)
491 /* 0000 */
492 RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY)
493
494 SEND (VFS5011_OUT_ENDPOINT, vfs5011_cmd_01)
495 RECV (VFS5011_IN_ENDPOINT_CTRL, 64)
496
497 SEND (VFS5011_OUT_ENDPOINT, vfs5011_cmd_1A)
498 /* 0000 */
499 RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY)
500
501 SEND (VFS5011_OUT_ENDPOINT, vfs5011_init_03)
502 /* 0000 */
503 RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY)
504
505 SEND (VFS5011_OUT_ENDPOINT, vfs5011_init_04)
506 /* 0000 */
507 RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY)
508 RECV (VFS5011_IN_ENDPOINT_DATA, 256)
509 RECV (VFS5011_IN_ENDPOINT_DATA, 64)
510
511 SEND (VFS5011_OUT_ENDPOINT, vfs5011_cmd_1A)
512 /* 0000 */
513 RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY)
514
515 SEND (VFS5011_OUT_ENDPOINT, vfs5011_init_05)
516 /* 0000 */
517 RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY)
518
519 SEND (VFS5011_OUT_ENDPOINT, vfs5011_cmd_01)
520 RECV (VFS5011_IN_ENDPOINT_CTRL, 64)
521
522 SEND (VFS5011_OUT_ENDPOINT, vfs5011_init_06)
523 /* 0000 */
524 RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY)
525 RECV (VFS5011_IN_ENDPOINT_DATA, 17216)
526 RECV (VFS5011_IN_ENDPOINT_DATA, 32)
527
528 SEND (VFS5011_OUT_ENDPOINT, vfs5011_init_07)
529 /* 0000 */
530 RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY)
531 RECV (VFS5011_IN_ENDPOINT_DATA, 45056)
532
533 SEND (VFS5011_OUT_ENDPOINT, vfs5011_init_08)
534 /* 0000 */
535 RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY)
536 RECV (VFS5011_IN_ENDPOINT_DATA, 16896)
537
538 SEND (VFS5011_OUT_ENDPOINT, vfs5011_init_09)
539 /* 0000 */
540 RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY)
541 RECV (VFS5011_IN_ENDPOINT_DATA, 4928)
542
543 SEND (VFS5011_OUT_ENDPOINT, vfs5011_init_10)
544 /* 0000 */
545 RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY)
546 RECV (VFS5011_IN_ENDPOINT_DATA, 5632)
547
548 SEND (VFS5011_OUT_ENDPOINT, vfs5011_init_11)
549 /* 0000 */
550 RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY)
551 RECV (VFS5011_IN_ENDPOINT_DATA, 5632)
552
553 SEND (VFS5011_OUT_ENDPOINT, vfs5011_init_12)
554 /* 0000 */
555 RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY)
556 RECV (VFS5011_IN_ENDPOINT_DATA, 3328)
557 RECV (VFS5011_IN_ENDPOINT_DATA, 64)
558
559 SEND (VFS5011_OUT_ENDPOINT, vfs5011_init_13)
560 /* 0000 */
561 RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY)
562
563 SEND (VFS5011_OUT_ENDPOINT, vfs5011_cmd_1A)
564 /* 0000 */
565 RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY)
566
567 SEND (VFS5011_OUT_ENDPOINT, vfs5011_init_03)
568 /* 0000 */
569 RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY)
570
571 SEND (VFS5011_OUT_ENDPOINT, vfs5011_init_14)
572 /* 0000 */
573 RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY)
574 RECV (VFS5011_IN_ENDPOINT_DATA, 4800)
575
576 SEND (VFS5011_OUT_ENDPOINT, vfs5011_cmd_1A)
577 /* 0000 */
578 RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY)
579
580 SEND (VFS5011_OUT_ENDPOINT, vfs5011_init_02)
581 /* 0000 */
582 RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY)
583
584 SEND (VFS5011_OUT_ENDPOINT, vfs5011_cmd_27)
585 RECV (VFS5011_IN_ENDPOINT_CTRL, 64)
586
587 SEND (VFS5011_OUT_ENDPOINT, vfs5011_cmd_1A)
588 /* 0000 */
589 RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY)
590
591 SEND (VFS5011_OUT_ENDPOINT, vfs5011_init_15)
592 /* 0000 */
593 RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY)
594
595 SEND (VFS5011_OUT_ENDPOINT, vfs5011_init_16)
596 RECV (VFS5011_IN_ENDPOINT_CTRL, 2368)
597 RECV (VFS5011_IN_ENDPOINT_CTRL, 64)
598 RECV (VFS5011_IN_ENDPOINT_DATA, 4800)
599
600 SEND (VFS5011_OUT_ENDPOINT, vfs5011_init_17)
601 /* 0000 */
602 RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY)
603
604 SEND (VFS5011_OUT_ENDPOINT, vfs5011_init_18)
605 /* 0000 */
606 RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY)
607
608 /*
609 * Windows driver does this and it works
610 * But in this driver this call never returns...
611 * RECV(VFS5011_IN_ENDPOINT_CTRL2, 8) //00D3054000
612 */
613 };
614
615 /* Initiate recording the image */
616 struct usb_action vfs5011_initiate_capture[] = {
617 SEND (VFS5011_OUT_ENDPOINT, vfs5011_cmd_04)
618 RECV (VFS5011_IN_ENDPOINT_DATA, 64)
619 RECV (VFS5011_IN_ENDPOINT_DATA, 84032)
620 RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY)
621
622 SEND (VFS5011_OUT_ENDPOINT, vfs5011_cmd_1A)
623 RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY)
624
625 SEND (VFS5011_OUT_ENDPOINT, vfs5011_prepare_00)
626 RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY)
627
628 SEND (VFS5011_OUT_ENDPOINT, vfs5011_cmd_1A)
629 RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY)
630
631 SEND (VFS5011_OUT_ENDPOINT, vfs5011_prepare_01)
632 RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY)
633
634 SEND (VFS5011_OUT_ENDPOINT, vfs5011_prepare_02)
635 RECV (VFS5011_IN_ENDPOINT_CTRL, 2368)
636 RECV (VFS5011_IN_ENDPOINT_CTRL, 64)
637 RECV (VFS5011_IN_ENDPOINT_DATA, 4800)
638
639 SEND (VFS5011_OUT_ENDPOINT, vfs5011_prepare_03)
640 RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 64, VFS5011_NORMAL_CONTROL_REPLY)
641 /*
642 * Windows driver does this and it works
643 * But in this driver this call never returns...
644 * RECV(VFS5011_IN_ENDPOINT_CTRL2, 8);
645 */
646
647 SEND (VFS5011_OUT_ENDPOINT, vfs5011_prepare_04)
648 RECV_CHECK (VFS5011_IN_ENDPOINT_CTRL, 2368, VFS5011_NORMAL_CONTROL_REPLY)
649
650 /*
651 * Windows driver does this and it works
652 * But in this driver this call never returns...
653 * RECV(VFS5011_IN_ENDPOINT_CTRL2, 8);
654 */
655 };
656
657 /* ====================== lifprint interface ======================= */
658
659 static void
660 13 activate_loop (FpiSsm *ssm, FpDevice *_dev)
661 {
662 13 enum {READ_TIMEOUT = 0};
663
664 13 FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
665 13 FpDeviceVfs5011 *self;
666
667 13 self = FPI_DEVICE_VFS5011 (_dev);
668
669 13 fp_dbg ("main_loop: state %d", fpi_ssm_get_cur_state (ssm));
670
671
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (self->deactivating)
672 {
673 fp_dbg ("deactivating, marking completed");
674 fpi_ssm_mark_completed (ssm);
675 return;
676 }
677
678
5/6
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 9 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
13 switch (fpi_ssm_get_cur_state (ssm))
679 {
680 1 case DEV_ACTIVATE_REQUEST_FPRINT:
681 1 self->init_sequence.stepcount =
682 G_N_ELEMENTS (vfs5011_initiate_capture);
683 1 self->init_sequence.actions = vfs5011_initiate_capture;
684 1 self->init_sequence.device = dev;
685
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (self->init_sequence.receive_buf == NULL)
686 1 self->init_sequence.receive_buf =
687 1 g_malloc0 (VFS5011_RECEIVE_BUF_SIZE);
688 1 self->init_sequence.timeout = 1000;
689 1 usb_exchange_async (ssm, &self->init_sequence, "ACTIVATE REQUEST");
690 1 break;
691
692 1 case DEV_ACTIVATE_INIT_COMPLETE:
693
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (self->init_sequence.receive_buf != NULL)
694 1 g_free (self->init_sequence.receive_buf);
695 1 self->init_sequence.receive_buf = NULL;
696 1 capture_init (self, MAX_CAPTURE_LINES, MAXLINES);
697 1 fpi_image_device_activate_complete (dev, NULL);
698 1 fpi_ssm_next_state (ssm);
699 1 break;
700
701 case DEV_ACTIVATE_READ_DATA:
702 9 capture_chunk_async (self,
703 fpi_device_get_usb_device (FP_DEVICE (dev)),
704 CAPTURE_LINES,
705 READ_TIMEOUT, ssm);
706 9 break;
707
708 1 case DEV_ACTIVATE_DATA_COMPLETE:
709 1 fpi_ssm_next_state_delayed (ssm, 1);
710 1 break;
711
712 1 case DEV_ACTIVATE_PREPARE_NEXT_CAPTURE:
713 1 self->init_sequence.stepcount =
714 G_N_ELEMENTS (vfs5011_initiate_capture);
715 1 self->init_sequence.actions = vfs5011_initiate_capture;
716 1 self->init_sequence.device = dev;
717
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (self->init_sequence.receive_buf == NULL)
718 1 self->init_sequence.receive_buf =
719 1 g_malloc0 (VFS5011_RECEIVE_BUF_SIZE);
720 1 self->init_sequence.timeout = VFS5011_DEFAULT_WAIT_TIMEOUT;
721 1 usb_exchange_async (ssm, &self->init_sequence, "PREPARE CAPTURE");
722 1 break;
723
724 }
725 }
726
727 static void
728 1 activate_loop_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
729 {
730 1 FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
731 1 FpDeviceVfs5011 *self;
732
733 1 self = FPI_DEVICE_VFS5011 (_dev);
734
735 1 fp_dbg ("finishing");
736
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (self->init_sequence.receive_buf != NULL)
737 1 g_free (self->init_sequence.receive_buf);
738 1 self->init_sequence.receive_buf = NULL;
739
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 if (!self->deactivating && !error)
740 {
741 1 submit_image (ssm, self, dev);
742 1 fpi_image_device_report_finger_status (dev, FALSE);
743 }
744
745 1 self->loop_running = FALSE;
746
747
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (self->deactivating)
748 1 fpi_image_device_deactivate_complete (dev, error);
749 else if (error)
750 fpi_image_device_session_error (dev, error);
751 else
752 start_scan (dev);
753 1 }
754
755
756 static void
757 1 open_loop (FpiSsm *ssm, FpDevice *_dev)
758 {
759 1 FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
760 1 FpDeviceVfs5011 *self;
761
762 1 self = FPI_DEVICE_VFS5011 (_dev);
763
764
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 switch (fpi_ssm_get_cur_state (ssm))
765 {
766 1 case DEV_OPEN_START:
767 1 self->init_sequence.stepcount =
768 G_N_ELEMENTS (vfs5011_initialization);
769 1 self->init_sequence.actions = vfs5011_initialization;
770 1 self->init_sequence.device = dev;
771 2 self->init_sequence.receive_buf =
772 1 g_malloc0 (VFS5011_RECEIVE_BUF_SIZE);
773 1 self->init_sequence.timeout = VFS5011_DEFAULT_WAIT_TIMEOUT;
774 1 usb_exchange_async (ssm, &self->init_sequence, "DEVICE OPEN");
775 1 break;
776 }
777 1 ;
778 1 }
779
780 static void
781 1 open_loop_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
782 {
783 1 FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
784 1 FpDeviceVfs5011 *self;
785
786 1 self = FPI_DEVICE_VFS5011 (_dev);
787 1 g_free (self->init_sequence.receive_buf);
788 1 self->init_sequence.receive_buf = NULL;
789
790 1 fpi_image_device_open_complete (dev, error);
791 1 }
792
793 static void
794 1 dev_open (FpImageDevice *dev)
795 {
796 1 FpiSsm *ssm;
797 1 GError *error = NULL;
798 1 FpDeviceVfs5011 *self;
799
800 1 self = FPI_DEVICE_VFS5011 (dev);
801 1 self->capture_buffer = g_new0 (unsigned char, CAPTURE_LINES * VFS5011_LINE_SIZE);
802
803
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if (!g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error))
804 {
805 fpi_image_device_open_complete (dev, error);
806 return;
807 }
808
809 1 ssm = fpi_ssm_new (FP_DEVICE (dev), open_loop, DEV_OPEN_NUM_STATES);
810 1 fpi_ssm_start (ssm, open_loop_complete);
811 }
812
813 static void
814 1 dev_close (FpImageDevice *dev)
815 {
816 1 GError *error = NULL;
817 1 FpDeviceVfs5011 *self = FPI_DEVICE_VFS5011 (dev);
818
819 1 g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)),
820 0, 0, &error);
821
822 1 g_free (self->capture_buffer);
823 1 g_slist_free_full (g_steal_pointer (&self->rows), g_free);
824
825 1 fpi_image_device_close_complete (dev, error);
826 1 }
827
828 static void
829 1 start_scan (FpImageDevice *dev)
830 {
831 1 FpDeviceVfs5011 *self;
832 1 FpiSsm *ssm;
833
834 1 self = FPI_DEVICE_VFS5011 (dev);
835 1 self->loop_running = TRUE;
836 1 fp_dbg ("creating ssm");
837 1 ssm = fpi_ssm_new (FP_DEVICE (dev), activate_loop, DEV_ACTIVATE_NUM_STATES);
838 1 fp_dbg ("starting ssm");
839 1 fpi_ssm_start (ssm, activate_loop_complete);
840 1 fp_dbg ("ssm done, getting out");
841 1 }
842
843 static void
844 1 dev_activate (FpImageDevice *dev)
845 {
846 1 FpDeviceVfs5011 *self;
847
848 1 self = FPI_DEVICE_VFS5011 (dev);
849 1 fp_dbg ("device initialized");
850 1 self->deactivating = FALSE;
851
852 1 start_scan (dev);
853 1 }
854
855 static void
856 1 dev_deactivate (FpImageDevice *dev)
857 {
858 1 FpDeviceVfs5011 *self;
859
860 1 self = FPI_DEVICE_VFS5011 (dev);
861
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (self->loop_running)
862 1 self->deactivating = TRUE;
863 else
864 fpi_image_device_deactivate_complete (dev, NULL);
865 1 }
866
867 static const FpIdEntry id_table[] = {
868 { /* Validity device from some Toshiba laptops */ .vid = 0x138a, .pid = 0x0010, },
869 { /* vfs5011 */ .vid = 0x138a, .pid = 0x0011, },
870 { /* Validity device from Lenovo Preferred Pro USB Fingerprint Keyboard KUF1256 */ .vid = 0x138a, .pid = 0x0015, },
871 { /* Validity device from Lenovo T440 laptops */ .vid = 0x138a, .pid = 0x0017, },
872 { /* one more Validity device */ .vid = 0x138a, .pid = 0x0018, },
873 { .vid = 0, .pid = 0, .driver_data = 0 },
874 };
875
876 static void
877 1 fpi_device_vfs5011_init (FpDeviceVfs5011 *self)
878 {
879 1 }
880 static void
881 120 fpi_device_vfs5011_class_init (FpDeviceVfs5011Class *klass)
882 {
883 120 FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
884 120 FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
885
886 120 dev_class->id = "vfs5011";
887 120 dev_class->full_name = "Validity VFS5011";
888 120 dev_class->type = FP_DEVICE_TYPE_USB;
889 120 dev_class->id_table = id_table;
890 120 dev_class->scan_type = FP_SCAN_TYPE_SWIPE;
891
892 120 img_class->img_open = dev_open;
893 120 img_class->img_close = dev_close;
894 120 img_class->activate = dev_activate;
895 120 img_class->deactivate = dev_deactivate;
896
897 120 img_class->bz3_threshold = 20;
898
899 120 img_class->img_width = VFS5011_IMAGE_WIDTH;
900 120 img_class->img_height = -1;
901 }
902