GCC Code Coverage Report


Directory: ./
File: libfprint/drivers/vfs0050.c
Date: 2024-09-16 14:36:32
Exec Total Coverage
Lines: 275 337 81.6%
Functions: 27 27 100.0%
Branches: 69 110 62.7%

Line Branch Exec Source
1 /*
2 * Validity VFS0050 driver for libfprint
3 * Copyright (C) 2015-2016 Konstantin Semenov <zemen17@gmail.com>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 #define FP_COMPONENT "vfs0050"
21
22 #include "drivers_api.h"
23 #include "vfs0050.h"
24
25
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 (FpDeviceVfs0050, fpi_device_vfs0050, FP_TYPE_IMAGE_DEVICE)
26
27 /* USB functions */
28
29 /* Callback for async_write */
30 static void
31 14 async_write_callback (FpiUsbTransfer *transfer, FpDevice *device,
32 gpointer user_data, GError *error)
33 {
34
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if (error)
35 {
36 fp_err ("USB write transfer: %s", error->message);
37 fpi_ssm_mark_failed (transfer->ssm, error);
38 return;
39 }
40
41 14 fpi_ssm_next_state (transfer->ssm);
42 }
43
44 /* Send data to EP1, the only out endpoint */
45 FP_GNUC_ACCESS (read_only, 3, 4)
46 static void
47 14 async_write (FpiSsm *ssm,
48 FpDevice *dev,
49 void *data,
50 int len)
51 {
52 14 FpiUsbTransfer *transfer;
53
54 14 transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
55 14 fpi_usb_transfer_fill_bulk_full (transfer, 0x01, data, len, NULL);
56 14 transfer->ssm = ssm;
57 14 transfer->short_is_error = TRUE;
58 14 fpi_usb_transfer_submit (transfer, VFS_USB_TIMEOUT, NULL,
59 async_write_callback, NULL);
60 14 }
61
62 /* Callback for async_read */
63 static void
64 18 async_read_callback (FpiUsbTransfer *transfer, FpDevice *device,
65 gpointer user_data, GError *error)
66 {
67 18 int ep = transfer->endpoint;
68
69
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if (error)
70 {
71 fp_err ("USB read transfer on endpoint %d: %s", ep - 0x80,
72 error->message);
73 fpi_ssm_mark_failed (transfer->ssm, error);
74 return;
75 }
76
77 18 fpi_ssm_next_state (transfer->ssm);
78 }
79
80 /* Receive data from the given ep and either discard or fill the given buffer */
81 static void
82 18 async_read (FpiSsm *ssm,
83 FpDevice *dev,
84 int ep,
85 void *data,
86 int len)
87 {
88 18 FpiUsbTransfer *transfer;
89 18 GDestroyNotify free_func = NULL;
90
91 18 ep |= FPI_USB_ENDPOINT_IN;
92
93 18 transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
94 18 transfer->ssm = ssm;
95 18 transfer->short_is_error = TRUE;
96
97
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 4 times.
18 if (data == NULL)
98 {
99 14 data = g_malloc0 (len);
100 14 free_func = g_free;
101 }
102
103 /* 0x83 is the only interrupt endpoint */
104
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 14 times.
18 if (ep == EP3_IN)
105 4 fpi_usb_transfer_fill_interrupt_full (transfer, ep, data, len, free_func);
106 else
107 14 fpi_usb_transfer_fill_bulk_full (transfer, ep, data, len, free_func);
108
109 18 fpi_usb_transfer_submit (transfer, VFS_USB_TIMEOUT, NULL,
110 async_read_callback, NULL);
111 18 }
112
113 /* Callback for async_abort */
114 static void
115 16 async_abort_callback (FpiUsbTransfer *transfer, FpDevice *device,
116 gpointer user_data, GError *error)
117 {
118 16 int ep = transfer->endpoint;
119
120 /* In normal case endpoint is empty */
121
2/4
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 16 times.
✗ Branch 5 not taken.
32 if (g_error_matches (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_TIMED_OUT) ||
122
1/2
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
32 (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0 && transfer->actual_length == 0))
123 {
124 16 g_clear_error (&error);
125 16 fpi_ssm_next_state (transfer->ssm);
126 16 return;
127 }
128
129 if (error)
130 {
131 fp_err ("USB write transfer: %s", error->message);
132 fpi_ssm_mark_failed (transfer->ssm, error);
133 return;
134 }
135
136 /* Don't stop process, only print warning */
137 fp_warn ("Endpoint %d had extra %zd bytes readable", ep - 0x80,
138 transfer->actual_length);
139
140 fpi_ssm_jump_to_state (transfer->ssm,
141 fpi_ssm_get_cur_state (transfer->ssm));
142 }
143
144 /* Receive data from the given ep; continues to the next state once no
145 * more data is available. Otherwise the current state is repeated. */
146 static void
147 16 async_abort (FpDevice *dev, FpiSsm *ssm, int ep)
148 {
149 16 FpiUsbTransfer *transfer;
150
151 16 ep |= FPI_USB_ENDPOINT_IN;
152
153 16 transfer = fpi_usb_transfer_new (dev);
154
155 /* 0x83 is the only interrupt endpoint */
156
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 10 times.
16 if (ep == EP3_IN)
157 6 fpi_usb_transfer_fill_interrupt (transfer, ep, VFS_USB_BUFFER_SIZE);
158 else
159 10 fpi_usb_transfer_fill_bulk (transfer, ep, VFS_USB_BUFFER_SIZE);
160
161 16 transfer->ssm = ssm;
162
163 16 fpi_usb_transfer_submit (transfer, VFS_USB_ABORT_TIMEOUT, NULL,
164 async_abort_callback, NULL);
165 16 }
166
167 /* Image processing functions */
168
169 /* Pixel getter for fpi_assemble_lines */
170 static unsigned char
171 230200 vfs0050_get_pixel (struct fpi_line_asmbl_ctx *ctx,
172 GSList * line, unsigned int x)
173 {
174 230200 return ((struct vfs_line *) line->data)->data[x];
175 }
176
177 /* Deviation getter for fpi_assemble_lines */
178 static int
179 147500 vfs0050_get_difference (struct fpi_line_asmbl_ctx *ctx,
180 GSList * line_list_1, GSList * line_list_2)
181 {
182 147500 struct vfs_line *line1 = line_list_1->data;
183 147500 struct vfs_line *line2 = line_list_2->data;
184 147500 const int shift = (VFS_IMAGE_WIDTH - VFS_NEXT_LINE_WIDTH) / 2 - 1;
185 147500 int res = 0;
186
187
2/2
✓ Branch 0 taken 4720000 times.
✓ Branch 1 taken 147500 times.
4867500 for (int i = 0; i < VFS_NEXT_LINE_WIDTH; ++i)
188 {
189 4720000 int x =
190 4720000 (int) line1->next_line_part[i] - (int) line2->data[shift + i];
191 4720000 res += x * x;
192 }
193 147500 return res;
194 }
195
196 #define VFS_NOISE_THRESHOLD 40
197
198 /* Checks whether line is noise or not using hardware parameters */
199 static char
200 1 is_noise (struct vfs_line *line)
201 {
202 1 int val1 = line->noise_hash_1;
203 1 int val2 = line->noise_hash_2;
204
205 1 if (val1 > VFS_NOISE_THRESHOLD &&
206 val1 < 256 - VFS_NOISE_THRESHOLD &&
207 val2 > VFS_NOISE_THRESHOLD && val2 < 256 - VFS_NOISE_THRESHOLD)
208 return 1;
209 return 0;
210 }
211
212 /* Parameters for fpi_assemble_lines */
213 static struct fpi_line_asmbl_ctx assembling_ctx = {
214 .line_width = VFS_IMAGE_WIDTH,
215 .max_height = VFS_MAX_HEIGHT,
216 .resolution = 10,
217 .median_filter_size = 25,
218 .max_search_offset = 100,
219 .get_deviation = vfs0050_get_difference,
220 .get_pixel = vfs0050_get_pixel,
221 };
222
223 /* Processes image before submitting */
224 static FpImage *
225 1 prepare_image (FpDeviceVfs0050 *vdev)
226 {
227 1 int height = vdev->bytes / VFS_LINE_SIZE;
228
229 /* Noise cleaning. IMHO, it works pretty well
230 I've not detected cases when it doesn't work or cuts a part of the finger
231 Noise arises at the end of scan when some water remains on the scanner */
232
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 while (height > 0)
233 {
234
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!is_noise (vdev->lines_buffer + height - 1))
235 break;
236 --height;
237 }
238
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (height > VFS_MAX_HEIGHT)
239 height = VFS_MAX_HEIGHT;
240
241 /* If image is not good enough */
242 if (height < VFS_IMAGE_WIDTH)
243 return NULL;
244
245 /* Building GSList */
246 1 GSList *lines = NULL;
247
248
2/2
✓ Branch 0 taken 3000 times.
✓ Branch 1 taken 1 times.
3001 for (int i = height - 1; i >= 0; --i)
249 3000 lines = g_slist_prepend (lines, vdev->lines_buffer + i);
250
251 /* Perform line assembling */
252 1 FpImage *img = fpi_assemble_lines (&assembling_ctx, lines, height);
253
254 1 g_slist_free (lines);
255 1 return img;
256 }
257
258 /* Processes and submits image after fingerprint received */
259 static void
260 1 submit_image (FpDeviceVfs0050 *self)
261 {
262 1 FpImageDevice *idev = FP_IMAGE_DEVICE (self);
263
264 /* We were not asked to submit image actually */
265
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!self->active)
266 return;
267
268 1 FpImage *img = prepare_image (self);
269
270
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!img)
271 fpi_image_device_retry_scan (idev, FP_DEVICE_RETRY_TOO_SHORT);
272 else
273 1 fpi_image_device_image_captured (idev, img);
274
275 /* Finger not on the scanner */
276 1 fpi_image_device_report_finger_status (idev, FALSE);
277 }
278
279 /* Proto functions */
280
281 /* SSM loop for clear_ep2 */
282 static void
283 18 clear_ep2_ssm (FpiSsm *ssm, FpDevice *dev)
284 {
285 18 char command04 = 0x04;
286
287
3/4
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
18 switch (fpi_ssm_get_cur_state (ssm))
288 {
289 6 case SUBSM1_COMMAND_04:
290 6 async_write (ssm, dev, &command04, sizeof (command04));
291 6 break;
292
293 6 case SUBSM1_RETURN_CODE:
294 6 async_read (ssm, dev, 1, NULL, 2);
295 6 break;
296
297 6 case SUBSM1_ABORT_2:
298 6 async_abort (dev, ssm, 2);
299 6 break;
300
301 default:
302 fp_err ("Unknown SUBSM1 state");
303 fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
304 }
305 18 }
306
307 /* Send command to clear EP2 */
308 static void
309 6 clear_ep2 (FpDevice *dev,
310 FpiSsm *ssm)
311 {
312 6 FpiSsm *subsm = fpi_ssm_new (dev, clear_ep2_ssm, SUBSM1_STATES);
313
314 6 fpi_ssm_start_subsm (ssm, subsm);
315 6 }
316
317 static void
318 28 send_control_packet_ssm (FpiSsm *ssm, FpDevice *dev)
319 {
320 28 FpDeviceVfs0050 *self = FPI_DEVICE_VFS0050 (dev);
321
322
7/8
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 4 times.
✓ Branch 7 taken 4 times.
✗ Branch 8 not taken.
28 switch (fpi_ssm_get_cur_state (ssm))
323 {
324 4 case SUBSM2_SEND_CONTROL:
325 4 async_write (ssm, dev, self->control_packet,
326 VFS_CONTROL_PACKET_SIZE);
327 4 break;
328
329 4 case SUBSM2_RETURN_CODE:
330 4 async_read (ssm, dev, 1, NULL, 2);
331 4 break;
332
333 4 case SUBSM2_SEND_COMMIT:
334 /* next_receive_* packets could be sent only in pair */
335
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (self->control_packet == next_receive_1)
336 {
337 self->control_packet = next_receive_2;
338 fpi_ssm_jump_to_state (ssm, SUBSM2_SEND_CONTROL);
339 break;
340 }
341 /* commit_out in Windows differs in each commit, but I send the same each time */
342 4 async_write (ssm, dev, commit_out, sizeof (commit_out));
343 4 break;
344
345 4 case SUBSM2_COMMIT_RESPONSE:
346 4 async_read (ssm, dev, 1, NULL, VFS_COMMIT_RESPONSE_SIZE);
347 4 break;
348
349 4 case SUBSM2_READ_EMPTY_INTERRUPT:
350 /* I don't know how to check result, it could be different
351 * NOTE: I guess this comment relates to the above read. */
352 4 async_read (ssm, dev, 3, self->interrupt, VFS_INTERRUPT_SIZE);
353 4 break;
354
355 4 case SUBSM2_ABORT_3:
356 /* Check that interrupt is empty */
357 4 if (memcmp
358
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 (self->interrupt, empty_interrupt, VFS_INTERRUPT_SIZE))
359 {
360 fp_err ("Unknown SUBSM2 state");
361 fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
362 break;
363 }
364 4 async_abort (dev, ssm, 3);
365 4 break;
366
367 4 case SUBSM2_CLEAR_EP2:
368 /* After turn_on Windows doesn't clear EP2 */
369
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 if (self->control_packet != turn_on)
370 3 clear_ep2 (dev, ssm);
371 else
372 1 fpi_ssm_next_state (ssm);
373 break;
374
375 default:
376 fp_err ("Unknown SUBSM2 state");
377 fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
378 }
379 28 }
380
381 /* Send device state control packet */
382 static void
383 4 send_control_packet (FpiSsm *ssm,
384 FpDevice *dev)
385 {
386 4 FpiSsm *subsm =
387 4 fpi_ssm_new (dev, send_control_packet_ssm, SUBSM2_STATES);
388
389 4 fpi_ssm_start_subsm (ssm, subsm);
390 4 }
391
392 /* Clears all fprint data */
393 static void
394 3 clear_data (FpDeviceVfs0050 *vdev)
395 {
396 3 g_free (vdev->lines_buffer);
397 3 vdev->lines_buffer = NULL;
398 3 vdev->memory = vdev->bytes = 0;
399 }
400
401 /* After receiving interrupt from EP3 */
402 static void
403 1 interrupt_callback (FpiUsbTransfer *transfer, FpDevice *device,
404 gpointer user_data, GError *error)
405 {
406 1 FpDeviceVfs0050 *self = FPI_DEVICE_VFS0050 (device);
407 1 unsigned char *interrupt = transfer->buffer;
408
409 /* we expect a cancellation error when the device is deactivating
410 * go into the SSM_CLEAR_EP2 state in that case. */
411
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
1 if (!self->active && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
412 {
413 g_error_free (error);
414 fpi_ssm_jump_to_state (transfer->ssm, SSM_CLEAR_EP2);
415 return;
416 }
417
418
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (error)
419 {
420 fp_err ("USB read interrupt transfer: %s",
421 error->message);
422 fpi_ssm_mark_failed (transfer->ssm, error);
423 return;
424 }
425
426 /* Standard interrupts */
427
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (memcmp (interrupt, interrupt1, VFS_INTERRUPT_SIZE) == 0 ||
428
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 memcmp (interrupt, interrupt2, VFS_INTERRUPT_SIZE) == 0 ||
429 memcmp (interrupt, interrupt3, VFS_INTERRUPT_SIZE) == 0)
430 {
431 /* Go to the next ssm stage */
432 1 fpi_ssm_next_state (transfer->ssm);
433 1 return;
434 }
435
436 /* When finger is on the scanner before turn_on */
437 if (interrupt[0] == 0x01)
438 {
439 fp_warn ("Finger is already on the scanner");
440
441 /* Go to the next ssm stage */
442 fpi_ssm_next_state (transfer->ssm);
443 return;
444 }
445
446 /* Unknown interrupt; abort the session */
447 fp_err ("Unknown interrupt '%02x:%02x:%02x:%02x:%02x'!",
448 interrupt[0] & 0xff, interrupt[1] & 0xff, interrupt[2] & 0xff,
449 interrupt[3] & 0xff, interrupt[4] & 0xff);
450
451 /* Abort ssm */
452 fpi_ssm_mark_failed (transfer->ssm,
453 fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
454 }
455
456 static void
457 25 receive_callback (FpiUsbTransfer *transfer, FpDevice *device,
458 gpointer user_data, GError *error)
459 {
460 25 FpDeviceVfs0050 *self = FPI_DEVICE_VFS0050 (device);
461
462
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
25 if (error && !g_error_matches (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_TIMED_OUT))
463 {
464 fp_err ("USB read transfer: %s", error->message);
465
466 fpi_ssm_mark_failed (transfer->ssm, error);
467 return;
468 }
469 if (error)
470 g_error_free (error);
471
472 /* Capture is done when there is no more data to transfer or device timed out */
473
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 24 times.
25 if (transfer->actual_length <= 0)
474 {
475 1 fpi_ssm_next_state (transfer->ssm);
476 }
477 else
478 {
479 24 self->bytes += transfer->actual_length;
480
481 /* Try reading more data */
482 24 fpi_ssm_jump_to_state (transfer->ssm,
483 fpi_ssm_get_cur_state (transfer->ssm));
484 }
485 }
486
487 /* Main SSM loop */
488 static void
489 44 activate_ssm (FpiSsm *ssm, FpDevice *dev)
490 {
491 44 FpImageDevice *idev = FP_IMAGE_DEVICE (dev);
492 44 FpDeviceVfs0050 *self = FPI_DEVICE_VFS0050 (dev);
493
494
11/13
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 3 times.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 25 times.
✓ Branch 9 taken 1 times.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 times.
44 switch (fpi_ssm_get_cur_state (ssm))
495 {
496 2 case SSM_INITIAL_ABORT_1:
497 2 async_abort (dev, ssm, 1);
498 2 break;
499
500 2 case SSM_INITIAL_ABORT_2:
501 2 async_abort (dev, ssm, 2);
502 2 break;
503
504 2 case SSM_INITIAL_ABORT_3:
505 2 async_abort (dev, ssm, 3);
506 2 break;
507
508 3 case SSM_CLEAR_EP2:
509 3 clear_ep2 (dev, ssm);
510 3 break;
511
512 3 case SSM_TURN_OFF:
513 /* Set control_packet argument */
514 3 self->control_packet = turn_off;
515
516 3 send_control_packet (ssm, dev);
517 3 break;
518
519 3 case SSM_TURN_ON:
520
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 if (!self->active)
521 {
522 /* The only correct exit */
523 2 fpi_ssm_mark_completed (ssm);
524
525
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (self->need_report)
526 {
527 1 fpi_image_device_deactivate_complete (idev,
528 NULL);
529 1 self->need_report = 0;
530 }
531 break;
532 }
533 /* Set control_packet argument */
534 1 self->control_packet = turn_on;
535
536 1 send_control_packet (ssm, dev);
537 1 break;
538
539 1 case SSM_ASK_INTERRUPT: {
540 1 FpiUsbTransfer *transfer;
541 /* Activated, light must be blinking now */
542
543 /* If we first time here, report that activate completed */
544
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (self->need_report)
545 {
546 1 fpi_image_device_activate_complete (idev, NULL);
547 1 self->need_report = 0;
548 }
549
550 /* Asynchronously enquire an interrupt */
551 1 transfer = fpi_usb_transfer_new (dev);
552 1 transfer->ssm = ssm;
553 1 transfer->short_is_error = TRUE;
554 1 fpi_usb_transfer_fill_interrupt (transfer, 0x83, VFS_INTERRUPT_SIZE);
555 1 fpi_usb_transfer_submit (transfer,
556 0,
557 fpi_device_get_cancellable (dev),
558 interrupt_callback, NULL);
559
560 /* I've put it here to be sure that data is cleared */
561 1 clear_data (self);
562
563 1 fpi_ssm_next_state (ssm);
564 1 break;
565 }
566
567 case SSM_WAIT_INTERRUPT:
568 /* TODO: This state is unused at this point. When we
569 * are in this state, then a user cancellation will
570 * cause deactivation. In that case, the USB transfer
571 * is cancelled and the device is set to not be active.
572 * We then go into SSM_CLEAR_EP2 based on the
573 * cancellation. */
574 break;
575
576 25 case SSM_RECEIVE_FINGER: {
577 25 FpiUsbTransfer *transfer;
578
579
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 24 times.
25 if (self->memory == 0)
580 {
581 /* Initialize fingerprint buffer */
582 1 g_free (self->lines_buffer);
583 1 self->memory = VFS_USB_BUFFER_SIZE;
584 1 self->lines_buffer = g_malloc0 (self->memory);
585 1 self->bytes = 0;
586
587 /* Finger is on the scanner */
588 1 fpi_image_device_report_finger_status (idev, TRUE);
589 }
590
591 /* Increase buffer size while it's insufficient */
592
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 25 times.
48 while (self->memory < self->bytes + VFS_USB_BUFFER_SIZE)
593 {
594 23 int pre_memory = self->memory;
595 23 self->memory += VFS_USB_BUFFER_SIZE;
596 46 self->lines_buffer =
597 23 (struct vfs_line *) g_realloc (self->lines_buffer,
598 self->memory);
599 23 memset ((guint8 *) self->lines_buffer + pre_memory, 0,
600 VFS_USB_BUFFER_SIZE);
601 }
602
603 /* Receive chunk of data */
604 25 transfer = fpi_usb_transfer_new (dev);
605 25 fpi_usb_transfer_fill_bulk_full (transfer, 0x82,
606 25 (guint8 *) self->lines_buffer + self->bytes,
607 VFS_USB_BUFFER_SIZE, NULL);
608 25 transfer->ssm = ssm;
609 25 fpi_usb_transfer_submit (transfer, VFS_USB_TIMEOUT, NULL,
610 receive_callback, NULL);
611 25 break;
612 }
613
614 1 case SSM_SUBMIT_IMAGE:
615 1 submit_image (self);
616 1 clear_data (self);
617
618 /* Wait for probable vdev->active changing */
619 1 fpi_ssm_next_state_delayed (ssm, VFS_SSM_TIMEOUT);
620 1 break;
621
622 1 case SSM_NEXT_RECEIVE:
623
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!self->active)
624 {
625 /* It's the last scan */
626 1 fpi_ssm_jump_to_state (ssm, SSM_CLEAR_EP2);
627 1 break;
628 }
629
630 /* Set control_packet argument */
631 self->control_packet = next_receive_1;
632
633 send_control_packet (ssm, dev);
634 break;
635
636 case SSM_WAIT_ANOTHER_SCAN:
637 /* Orange light is on now */
638 fpi_ssm_jump_to_state_delayed (ssm, SSM_TURN_ON, VFS_SSM_ORANGE_TIMEOUT);
639 break;
640
641 default:
642 fp_err ("Unknown state");
643 fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
644 }
645 44 }
646
647 /* Driver functions */
648
649 /* Callback for dev_activate ssm */
650 static void
651 1 dev_activate_callback (FpiSsm *ssm, FpDevice *dev, GError *error)
652 {
653 1 FpDeviceVfs0050 *self = FPI_DEVICE_VFS0050 (dev);
654
655 1 self->ssm_active = 0;
656
657
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (error)
658 {
659 g_warning ("Unhandled device activation error: %s", error->message);
660 g_error_free (error);
661 }
662
663 1 }
664
665 /* Activate device */
666 static void
667 1 dev_activate (FpImageDevice *idev)
668 {
669 1 FpDeviceVfs0050 *self = FPI_DEVICE_VFS0050 (idev);
670
671 /* Initialize flags */
672 1 self->active = 1;
673 1 self->need_report = 1;
674 1 self->ssm_active = 1;
675
676 1 FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (idev), activate_ssm, SSM_STATES);
677
678 1 fpi_ssm_start (ssm, dev_activate_callback);
679 1 }
680
681 /* Deactivate device */
682 static void
683 1 dev_deactivate (FpImageDevice *idev)
684 {
685 1 FpDeviceVfs0050 *self = FPI_DEVICE_VFS0050 (idev);
686
687
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!self->ssm_active)
688 {
689 fpi_image_device_deactivate_complete (idev, NULL);
690 return;
691 }
692
693 /* Initialize flags */
694 1 self->active = 0;
695 1 self->need_report = 1;
696 }
697
698 /* Callback for dev_open ssm */
699 static void
700 1 dev_open_callback (FpiSsm *ssm, FpDevice *dev, GError *error)
701 {
702 /* Notify open complete */
703 1 fpi_image_device_open_complete (FP_IMAGE_DEVICE (dev), error);
704 1 }
705
706 /* Open device */
707 static void
708 1 dev_open (FpImageDevice *idev)
709 {
710 1 GError *error = NULL;
711
712 /* Claim usb interface */
713
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 (idev)), 0, 0, &error))
714 {
715 fpi_image_device_open_complete (idev, error);
716 return;
717 }
718
719 /* Clearing previous device state */
720 1 FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (idev), activate_ssm, SSM_STATES);
721
722 1 fpi_ssm_start (ssm, dev_open_callback);
723 }
724
725 /* Close device */
726 static void
727 1 dev_close (FpImageDevice *idev)
728 {
729 1 GError *error = NULL;
730 1 FpDeviceVfs0050 *self = FPI_DEVICE_VFS0050 (idev);
731
732 1 clear_data (self);
733
734 /* Release usb interface */
735 1 g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (idev)),
736 0, 0, &error);
737
738 /* Notify close complete */
739 1 fpi_image_device_close_complete (idev, error);
740 1 }
741
742 /* Usb id table of device */
743 static const FpIdEntry id_table[] = {
744 {.vid = 0x138a, .pid = 0x0050, },
745 {.vid = 0, .pid = 0, .driver_data = 0},
746 };
747
748 static void
749 1 fpi_device_vfs0050_init (FpDeviceVfs0050 *self)
750 {
751 1 }
752 static void
753 120 fpi_device_vfs0050_class_init (FpDeviceVfs0050Class *klass)
754 {
755 120 FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
756 120 FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
757
758 120 dev_class->id = "vfs0050";
759 120 dev_class->full_name = "Validity VFS0050";
760 120 dev_class->type = FP_DEVICE_TYPE_USB;
761 120 dev_class->id_table = id_table;
762 120 dev_class->scan_type = FP_SCAN_TYPE_SWIPE;
763
764 120 img_class->img_open = dev_open;
765 120 img_class->img_close = dev_close;
766 120 img_class->activate = dev_activate;
767 120 img_class->deactivate = dev_deactivate;
768
769 120 img_class->bz3_threshold = 24;
770
771 120 img_class->img_width = VFS_IMAGE_WIDTH;
772 120 img_class->img_height = -1;
773 }
774