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 |