GCC Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 3.6% 18 / 0 / 498
Functions: 10.0% 3 / 0 / 30
Branches: 2.6% 4 / 0 / 156

libfprint/drivers/vfs101.c
Line Branch Exec Source
1 /*
2 * Validity VFS101 driver for libfprint
3 * Copyright (C) 2011 Sergio Cerlesi <sergio.cerlesi@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 "vfs101"
21
22 #include "drivers_api.h"
23
24 /* Input-Output usb endpoint */
25 #define EP_IN(n) (n | FPI_USB_ENDPOINT_IN)
26 #define EP_OUT(n) (n | FPI_USB_ENDPOINT_OUT)
27
28 /* Usb bulk timeout */
29 #define BULK_TIMEOUT 100
30
31 /* The device send back the image into block of 16 frames of 292 bytes */
32 #define VFS_FRAME_SIZE 292
33 #define VFS_BLOCK_SIZE 16 * VFS_FRAME_SIZE
34
35 /* Buffer height */
36 #define VFS_BUFFER_HEIGHT 5000
37
38 /* Buffer size */
39 #define VFS_BUFFER_SIZE (VFS_BUFFER_HEIGHT * VFS_FRAME_SIZE)
40
41 /* Image width */
42 #define VFS_IMG_WIDTH 200
43
44 /* Maximum image height */
45 #define VFS_IMG_MAX_HEIGHT 1023
46
47 /* Minimum image height */
48 #define VFS_IMG_MIN_HEIGHT 200
49
50 /* Scan level threshold */
51 #define VFS_IMG_SLT_BEGIN 768
52 #define VFS_IMG_SLT_END 64
53 #define VFS_IMG_SLT_LINES 4
54
55 /* Minimum image level */
56 #define VFS_IMG_MIN_IMAGE_LEVEL 144
57
58 /* Best image contrast */
59 #define VFS_IMG_BEST_CONTRAST 128
60
61 /* Device parameters address */
62 #define VFS_PAR_000E 0x000e
63 #define VFS_PAR_0011 0x0011
64 #define VFS_PAR_THRESHOLD 0x0057
65 #define VFS_PAR_STATE_3 0x005e
66 #define VFS_PAR_STATE_5 0x005f
67 #define VFS_PAR_INFO_RATE 0x0062
68 #define VFS_PAR_0076 0x0076
69 #define VFS_PAR_INFO_CONTRAST 0x0077
70 #define VFS_PAR_0078 0x0078
71
72 /* Device regiones address */
73 #define VFS_REG_IMG_EXPOSURE 0xff500e
74 #define VFS_REG_IMG_CONTRAST 0xff5038
75
76 /* Device settings */
77 #define VFS_VAL_000E 0x0001
78 #define VFS_VAL_0011 0x0008
79 #define VFS_VAL_THRESHOLD 0x0096
80 #define VFS_VAL_STATE_3 0x0064
81 #define VFS_VAL_STATE_5 0x00c8
82 #define VFS_VAL_INFO_RATE 0x0001
83 #define VFS_VAL_0076 0x0012
84 #define VFS_VAL_0078 0x2230
85 #define VFS_VAL_IMG_EXPOSURE 0x21c0
86
87 /* Structure for Validity device */
88 struct _FpDeviceVfs101
89 {
90 FpImageDevice parent;
91
92 /* Action state */
93 gboolean active;
94 gboolean deactivate;
95
96 /* Sequential number */
97 unsigned int seqnum;
98
99 /* Buffer for input/output */
100 unsigned char *buffer;
101
102 /* Length of data to send or received */
103 unsigned int length;
104
105 /* Ignore usb error */
106 int ignore_error;
107
108 /* Loop counter */
109 int counter;
110
111 /* Image contrast */
112 int contrast;
113
114 /* Best contrast */
115 int best_contrast;
116
117 /* Best contrast level */
118 int best_clevel;
119
120 /* Bottom line of image */
121 int bottom;
122
123 /* Image height */
124 int height;
125 };
126 G_DECLARE_FINAL_TYPE (FpDeviceVfs101, fpi_device_vfs101, FPI, DEVICE_VFS101,
127 FpImageDevice);
128
4/6
fpi_device_vfs101_class_intern_init:
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 125 times.
fpi_device_vfs101_get_type:
✓ Branch 2 → 3 taken 125 times.
✓ Branch 2 → 7 taken 24 times.
✓ Branch 4 → 5 taken 125 times.
✗ Branch 4 → 7 not taken.
399 G_DEFINE_TYPE (FpDeviceVfs101, fpi_device_vfs101, FP_TYPE_IMAGE_DEVICE);
129
130 /* Return byte at specified position */
131 static inline unsigned char
132 byte (int position, int value)
133 {
134 return (value >> (position * 8)) & 0xff;
135 }
136
137 /* Return sequential number */
138 static inline unsigned short
139 get_seqnum (int h, int l)
140 {
141 return (h << 8) | l;
142 }
143
144 /* Check sequential number */
145 static inline int
146 check_seqnum (FpDeviceVfs101 *vdev)
147 {
148 if ((byte (0, vdev->seqnum) == vdev->buffer[0]) &&
149 (byte (1, vdev->seqnum) == vdev->buffer[1]))
150 return 0;
151 else
152 return 1;
153 }
154
155 /* Internal result codes */
156 enum {
157 RESULT_RETRY,
158 RESULT_RETRY_SHORT,
159 RESULT_RETRY_REMOVE,
160 RESULT_COUNT,
161 };
162
163 /* Dump buffer for debug */
164 #define dump_buffer(buf) \
165 fp_dbg ("%02x %02x %02x %02x %02x %02x %02x %02x", \
166 buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], buf[12], buf[13] \
167 )
168
169 /* Callback of asynchronous send */
170 static void
171 async_send_cb (FpiUsbTransfer *transfer, FpDevice *device,
172 gpointer user_data, GError *error)
173 {
174 FpImageDevice *dev = FP_IMAGE_DEVICE (device);
175 FpDeviceVfs101 *self = FPI_DEVICE_VFS101 (dev);
176
177 /* Skip error check if ignore_error is set */
178 if (error)
179 {
180 if (!self->ignore_error)
181 {
182 fpi_ssm_mark_failed (transfer->ssm, error);
183 return;
184 }
185 else
186 {
187 fp_dbg ("Ignoring send error: %s", error->message);
188 g_error_free (error);
189 }
190 }
191 /* Reset ignore_error flag */
192 self->ignore_error = FALSE;
193
194 /* Dump buffer for debug */
195 dump_buffer (self->buffer);
196
197 fpi_ssm_next_state (transfer->ssm);
198 }
199
200 /* Submit asynchronous send */
201 static void
202 async_send (FpiSsm *ssm,
203 FpImageDevice *dev)
204 {
205 FpDeviceVfs101 *self = FPI_DEVICE_VFS101 (dev);
206 FpiUsbTransfer *transfer;
207
208 transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
209
210 /* Put sequential number into the buffer */
211 self->seqnum++;
212 self->buffer[0] = byte (0, self->seqnum);
213 self->buffer[1] = byte (1, self->seqnum);
214
215 /* Prepare bulk transfer */
216 fpi_usb_transfer_fill_bulk_full (transfer, EP_OUT (1),
217 self->buffer, self->length, NULL);
218 transfer->ssm = ssm;
219 transfer->short_is_error = TRUE;
220 fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
221 async_send_cb, NULL);
222 }
223
224 /* Callback of asynchronous recv */
225 static void
226 async_recv_cb (FpiUsbTransfer *transfer, FpDevice *device,
227 gpointer user_data, GError *error)
228 {
229 FpImageDevice *dev = FP_IMAGE_DEVICE (device);
230 FpDeviceVfs101 *self = FPI_DEVICE_VFS101 (dev);
231
232 /* Skip error check if ignore_error is set */
233 if (!self->ignore_error)
234 {
235 if (error)
236 {
237 /* Transfer not completed, return IO error */
238 fpi_ssm_mark_failed (transfer->ssm, error);
239 return;
240 }
241
242 if (check_seqnum (self))
243 {
244 /* Sequential number received mismatch, return protocol error */
245 fp_err ("seqnum mismatch, got %04x, expected %04x",
246 get_seqnum (self->buffer[1], self->buffer[0]),
247 self->seqnum);
248 fpi_ssm_mark_failed (transfer->ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
249 return;
250 }
251 }
252
253 g_clear_pointer (&error, g_error_free);
254
255 /* Reset ignore_error flag */
256 self->ignore_error = FALSE;
257
258 /* Dump buffer for debug */
259 dump_buffer (self->buffer);
260
261 /* Set length of received data */
262 self->length = transfer->actual_length;
263
264 fpi_ssm_next_state (transfer->ssm);
265 }
266
267 /* Submit asynchronous recv */
268 static void
269 async_recv (FpiSsm *ssm,
270 FpImageDevice *dev)
271 {
272 FpDeviceVfs101 *self = FPI_DEVICE_VFS101 (dev);
273 FpiUsbTransfer *transfer;
274
275 /* Allocation of transfer */
276 transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
277
278 /* Prepare bulk transfer */
279 fpi_usb_transfer_fill_bulk_full (transfer, EP_IN (1), self->buffer,
280 0x0f, NULL);
281 transfer->ssm = ssm;
282 fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
283 async_recv_cb, NULL);
284 }
285
286 static void async_load (FpiSsm *ssm,
287 FpImageDevice *dev);
288
289 /* Callback of asynchronous load */
290 static void
291 async_load_cb (FpiUsbTransfer *transfer, FpDevice *device,
292 gpointer user_data, GError *error)
293 {
294 FpImageDevice *dev = FP_IMAGE_DEVICE (device);
295 FpDeviceVfs101 *self = FPI_DEVICE_VFS101 (dev);
296
297 /* Skip error check if ignore_error is set */
298 if (!self->ignore_error)
299 {
300 if (error)
301 {
302 /* Transfer not completed */
303 fpi_ssm_mark_failed (transfer->ssm, error);
304 return;
305 }
306
307 if (transfer->actual_length % VFS_FRAME_SIZE)
308 {
309 /* Received incomplete frame, return protocol error */
310 fp_err ("received incomplete frame");
311 fpi_ssm_mark_failed (transfer->ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
312 return;
313 }
314 }
315
316 /* Any error has been ignored. */
317 g_clear_pointer (&error, g_error_free);
318
319 /* Increase image length */
320 self->length += transfer->actual_length;
321
322 if (transfer->actual_length == VFS_BLOCK_SIZE)
323 {
324 if ((VFS_BUFFER_SIZE - self->length) < VFS_BLOCK_SIZE)
325 {
326 /* Buffer full, image too large, return no memory error */
327 fp_err ("buffer full, image too large");
328 fpi_ssm_mark_failed (transfer->ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
329 return;
330 }
331 else
332 {
333 /* Image load not completed, submit another asynchronous load */
334 async_load (transfer->ssm, dev);
335 }
336 }
337 else
338 {
339 /* Reset ignore_error flag */
340 self->ignore_error = FALSE;
341
342 /* Image load completed, go to next state */
343 self->height = self->length / VFS_FRAME_SIZE;
344 fp_dbg ("image loaded, height = %d", self->height);
345 fpi_ssm_next_state (transfer->ssm);
346 }
347 }
348
349 /* Submit asynchronous load */
350 static void
351 async_load (FpiSsm *ssm,
352 FpImageDevice *dev)
353 {
354 FpDeviceVfs101 *self = FPI_DEVICE_VFS101 (dev);
355 FpiUsbTransfer *transfer;
356 unsigned char *buffer;
357
358 /* Allocation of transfer */
359 transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
360
361 /* Append new data into the buffer */
362 buffer = self->buffer + self->length;
363
364 /* Prepare bulk transfer */
365 fpi_usb_transfer_fill_bulk_full (transfer, EP_IN (2), buffer,
366 VFS_BLOCK_SIZE, NULL);
367 transfer->ssm = ssm;
368 fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
369 async_load_cb, NULL);
370 }
371
372 /* Swap ssm states */
373 enum {
374 M_SWAP_SEND,
375 M_SWAP_RECV,
376 M_SWAP_NUM_STATES,
377 };
378
379 /* Exec swap sequential state machine */
380 static void
381 m_swap_state (FpiSsm *ssm, FpDevice *dev)
382 {
383 switch (fpi_ssm_get_cur_state (ssm))
384 {
385 case M_SWAP_SEND:
386 /* Send data */
387 async_send (ssm, FP_IMAGE_DEVICE (dev));
388 break;
389
390 case M_SWAP_RECV:
391 /* Recv response */
392 async_recv (ssm, FP_IMAGE_DEVICE (dev));
393 break;
394 }
395 }
396
397 /* Start swap sequential state machine */
398 static void
399 m_swap (FpiSsm *ssm,
400 FpImageDevice *dev,
401 unsigned char *data,
402 size_t length)
403 {
404 FpDeviceVfs101 *self = FPI_DEVICE_VFS101 (dev);
405 FpiSsm *subsm;
406
407 /* Prepare data for sending */
408 memcpy (self->buffer, data, length);
409 memset (self->buffer + length, 0, 16 - length);
410 self->length = length;
411
412 /* Start swap ssm */
413 subsm = fpi_ssm_new (FP_DEVICE (dev), m_swap_state, M_SWAP_NUM_STATES);
414 fpi_ssm_start_subsm (ssm, subsm);
415 }
416
417 /* Retrieve fingerprint image */
418 static void
419 vfs_get_print (FpiSsm *ssm,
420 FpImageDevice *dev,
421 unsigned int param,
422 int type)
423 {
424 unsigned char data[2][0x0e] = {
425 { 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
426 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01 },
427 { 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
428 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01 }
429 };
430
431 fp_dbg ("param = %04x, type = %d", param, type);
432
433 /* Prepare data for sending */
434 data[type][6] = byte (0, param);
435 data[type][7] = byte (1, param);
436
437 /* Run swap sequential state machine */
438 m_swap (ssm, dev, data[type], 0x0e);
439 }
440
441 /* Set a parameter value on the device */
442 static void
443 vfs_set_param (FpiSsm *ssm,
444 FpImageDevice *dev,
445 unsigned int param,
446 unsigned int value)
447 {
448 unsigned char data[0x0a] = { 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00 };
449
450 fp_dbg ("param = %04x, value = %04x", param, value);
451
452 /* Prepare data for sending */
453 data[6] = byte (0, param);
454 data[7] = byte (1, param);
455 data[8] = byte (0, value);
456 data[9] = byte (1, value);
457
458 /* Run swap sequential state machine */
459 m_swap (ssm, dev, data, 0x0a);
460 }
461
462 /* Abort previous print */
463 static void
464 vfs_abort_print (FpiSsm *ssm,
465 FpImageDevice *dev)
466 {
467 unsigned char data[0x06] = { 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00 };
468
469 G_DEBUG_HERE ();
470
471 /* Run swap sequential state machine */
472 m_swap (ssm, dev, data, 0x06);
473 }
474
475 /* Poke a value on a region */
476 static void
477 vfs_poke (FpiSsm *ssm,
478 FpImageDevice *dev,
479 unsigned int addr,
480 unsigned int value,
481 unsigned int size)
482 {
483 unsigned char data[0x0f] = { 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
484
485 fp_dbg ("addr = %04x, value = %04x", addr, value);
486
487 /* Prepare data for sending */
488 data[6] = byte (0, addr);
489 data[7] = byte (1, addr);
490 data[8] = byte (2, addr);
491 data[9] = byte (3, addr);
492 data[10] = byte (0, value);
493 data[11] = byte (1, value);
494 data[12] = byte (2, value);
495 data[13] = byte (3, value);
496 data[14] = byte (0, size);
497
498 /* Run swap sequential state machine */
499 m_swap (ssm, dev, data, 0x0f);
500 }
501
502 /* Get current finger state */
503 static void
504 vfs_get_finger_state (FpiSsm *ssm,
505 FpImageDevice *dev)
506 {
507 unsigned char data[0x06] = { 0x00, 0x00, 0x00, 0x00, 0x16, 0x00 };
508
509 G_DEBUG_HERE ();
510
511 /* Run swap sequential state machine */
512 m_swap (ssm, dev, data, 0x06);
513 }
514
515 /* Load raw image from reader */
516 static void
517 vfs_img_load (FpiSsm *ssm,
518 FpImageDevice *dev)
519 {
520 FpDeviceVfs101 *self = FPI_DEVICE_VFS101 (dev);
521
522 G_DEBUG_HERE ();
523
524 /* Reset buffer length */
525 self->length = 0;
526
527 /* Reset image properties */
528 self->bottom = 0;
529 self->height = -1;
530
531 /* Asynchronous load */
532 async_load (ssm, dev);
533 }
534
535 #define offset(x, y) ((x) + ((y) * VFS_FRAME_SIZE))
536
537 /* Screen image to remove noise and find bottom line and height of image */
538 static void
539 img_screen (FpDeviceVfs101 *vdev)
540 {
541 int y, x, count, top;
542 long int level;
543 int last_line = vdev->height - 1;
544
545 fp_dbg ("image height before screen = %d", vdev->height);
546
547 count = 0;
548
549 /* Image returned from sensor can contain many empty lines,
550 * for remove these lines compare byte 282-283 (scan level information)
551 * with two different thresholds, one for the begin of finger image and
552 * one for the end. To increase stability of the code use a counter
553 * of lines that satisfy the threshold.
554 */
555 for (y = last_line, top = last_line; y >= 0; y--)
556 {
557 /* Take image scan level */
558 level = vdev->buffer[offset (283, y)] * 256 +
559 vdev->buffer[offset (282, y)];
560
561 fp_dbg ("line = %d, scan level = %ld", y, level);
562
563 if (level >= VFS_IMG_SLT_BEGIN && top == last_line)
564 {
565 /* Begin threshold satisfied */
566 if (count < VFS_IMG_SLT_LINES)
567 {
568 /* Increase count */
569 count++;
570 }
571 else
572 {
573 /* Found top fingerprint line */
574 top = y + VFS_IMG_SLT_LINES;
575 count = 0;
576 }
577 }
578 else if ((level < VFS_IMG_SLT_END || level >= 65535) &&
579 top != last_line)
580 {
581 /* End threshold satisfied */
582 if (count < VFS_IMG_SLT_LINES)
583 {
584 /* Increase count */
585 count++;
586 }
587 else
588 {
589 /* Found bottom fingerprint line */
590 vdev->bottom = y + VFS_IMG_SLT_LINES + 1;
591 break;
592 }
593 }
594 else
595 {
596 /* Not threshold satisfied, reset count */
597 count = 0;
598 }
599 }
600
601 vdev->height = top - vdev->bottom + 1;
602
603 /* Check max height */
604 if (vdev->height > VFS_IMG_MAX_HEIGHT)
605 vdev->height = VFS_IMG_MAX_HEIGHT;
606
607 fp_dbg ("image height after screen = %d", vdev->height);
608
609 /* Scan image and remove noise */
610 for (y = vdev->bottom; y <= top; y++)
611 for (x = 6; x < VFS_IMG_WIDTH + 6; x++)
612 if (vdev->buffer[offset (x, y)] > VFS_IMG_MIN_IMAGE_LEVEL)
613 vdev->buffer[offset (x, y)] = 255;
614 };
615
616 /* Copy image from reader buffer and put it into image data */
617 static void
618 img_copy (FpDeviceVfs101 *self, FpImage *img)
619 {
620 unsigned int line;
621 unsigned char *img_buffer = img->data;
622 unsigned char *vdev_buffer = self->buffer + (self->bottom * VFS_FRAME_SIZE) + 6;
623
624 for (line = 0; line < img->height; line++)
625 {
626 /* Copy image line from reader buffer to image data */
627 memcpy (img_buffer, vdev_buffer, VFS_IMG_WIDTH);
628
629 /* Next line of reader buffer */
630 vdev_buffer = vdev_buffer + VFS_FRAME_SIZE;
631
632 /* Next line of image buffer */
633 img_buffer = img_buffer + VFS_IMG_WIDTH;
634 }
635 }
636
637 /* Extract fingerpint image from raw data */
638 static void
639 img_extract (FpiSsm *ssm,
640 FpImageDevice *dev)
641 {
642 FpDeviceVfs101 *self = FPI_DEVICE_VFS101 (dev);
643 FpImage *img;
644
645 /* Screen image to remove noise and find top and bottom line */
646 img_screen (self);
647
648 /* Check image height */
649 if (self->height < VFS_IMG_MIN_HEIGHT)
650 {
651 /* Image too short */
652 self->height = 0;
653 fpi_image_device_retry_scan (dev, FP_DEVICE_RETRY_TOO_SHORT);
654 return;
655 }
656
657 /* Create new image */
658 img = fp_image_new (self->height, VFS_IMG_WIDTH);
659 img->width = VFS_IMG_WIDTH;
660 img->height = self->height;
661 img->flags = FPI_IMAGE_V_FLIPPED;
662
663 /* Copy data into image */
664 img_copy (self, img);
665
666 /* Notify image captured */
667 fpi_image_device_image_captured (dev, img);
668 };
669
670 /* Finger states */
671 enum {
672 VFS_FINGER_EMPTY,
673 VFS_FINGER_PRESENT,
674 VFS_FINGER_UNKNOWN,
675 };
676
677 /* Return finger state */
678 static inline int
679 vfs_finger_state (FpDeviceVfs101 *vdev)
680 {
681 /* Check finger state */
682 switch (vdev->buffer[0x0a])
683 {
684 case 0x00:
685 case 0x01:
686 /* Finger is empty */
687 return VFS_FINGER_EMPTY;
688 break;
689
690 case 0x02:
691 case 0x03:
692 case 0x04:
693 case 0x05:
694 case 0x06:
695 /* Finger is present */
696 return VFS_FINGER_PRESENT;
697 break;
698
699 default:
700 return VFS_FINGER_UNKNOWN;
701 }
702 };
703
704 /* Check contrast of image */
705 static void
706 vfs_check_contrast (FpDeviceVfs101 *vdev)
707 {
708 int y;
709 long int count = 0;
710
711 if (vdev->height <= 0)
712 return;
713
714 /* Check difference from byte 4 to byte 5 for verify contrast of image */
715 for (y = 0; y < vdev->height; y++)
716 count = count + vdev->buffer[offset (5, y)] - vdev->buffer[offset (4, y)];
717 count = count / vdev->height;
718
719 if (count < 16)
720 {
721 /* Contrast not valid, retry */
722 vdev->contrast++;
723 return;
724 }
725
726 fp_dbg ("contrast = %d, level = %ld", vdev->contrast, count);
727
728 if (labs (count - VFS_IMG_BEST_CONTRAST) < abs (vdev->best_clevel - VFS_IMG_BEST_CONTRAST))
729 {
730 /* Better contrast found, use it */
731 vdev->best_contrast = vdev->contrast;
732 vdev->best_clevel = count;
733 }
734 }
735
736 /* Loop ssm states */
737 enum {
738 /* Step 0 - Scan finger */
739 M_LOOP_0_GET_PRINT,
740 M_LOOP_0_SLEEP,
741 M_LOOP_0_GET_STATE,
742 M_LOOP_0_LOAD_IMAGE,
743 M_LOOP_0_EXTRACT_IMAGE,
744 M_LOOP_0_CHECK_ACTION,
745
746 /* Step 1 - Scan failed */
747 M_LOOP_1_GET_STATE,
748 M_LOOP_1_CHECK_STATE,
749 M_LOOP_1_GET_PRINT,
750 M_LOOP_1_LOAD_IMAGE,
751 M_LOOP_1_LOOP,
752 M_LOOP_1_SLEEP,
753
754 /* Step 2 - Abort print */
755 M_LOOP_2_ABORT_PRINT,
756 M_LOOP_2_LOAD_IMAGE,
757
758 /* Step 3 - Wait aborting */
759 M_LOOP_3_GET_PRINT,
760 M_LOOP_3_LOAD_IMAGE,
761 M_LOOP_3_CHECK_IMAGE,
762 M_LOOP_3_LOOP,
763
764 /* Number of states */
765 M_LOOP_NUM_STATES,
766 };
767
768 /* Exec loop sequential state machine */
769 static void
770 m_loop_state (FpiSsm *ssm, FpDevice *_dev)
771 {
772 FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
773 FpDeviceVfs101 *self = FPI_DEVICE_VFS101 (_dev);
774
775 /* Complete if deactivation was requested */
776 if (self->deactivate)
777 {
778 fpi_ssm_mark_completed (ssm);
779 return;
780 }
781
782 switch (fpi_ssm_get_cur_state (ssm))
783 {
784 case M_LOOP_0_GET_PRINT:
785 /* Send get print command to the reader */
786 vfs_get_print (ssm, dev, VFS_BUFFER_HEIGHT, 1);
787 break;
788
789 case M_LOOP_0_SLEEP:
790 /* Wait fingerprint scanning */
791 fpi_ssm_next_state_delayed (ssm, 50);
792 break;
793
794 case M_LOOP_0_GET_STATE:
795 /* Get finger state */
796 vfs_get_finger_state (ssm, dev);
797 break;
798
799 case M_LOOP_0_LOAD_IMAGE:
800 /* Check finger state */
801 switch (vfs_finger_state (self))
802 {
803 case VFS_FINGER_EMPTY:
804 fpi_image_device_report_finger_status (dev, FALSE);
805
806 /* Finger isn't present, loop */
807 fpi_ssm_jump_to_state (ssm, M_LOOP_0_SLEEP);
808 break;
809
810 case VFS_FINGER_PRESENT:
811 fpi_image_device_report_finger_status (dev, TRUE);
812
813 /* Load image from reader */
814 self->ignore_error = TRUE;
815 vfs_img_load (ssm, dev);
816 break;
817
818 default:
819 fpi_image_device_report_finger_status (dev, FALSE);
820
821 /* Unknown state */
822 fp_err ("unknown device state 0x%02x",
823 self->buffer[0x0a]);
824 fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
825 break;
826 }
827 break;
828
829 case M_LOOP_0_EXTRACT_IMAGE:
830 /* Fingerprint is loaded, extract image from raw data */
831 img_extract (ssm, dev);
832
833 /* Wait handling image */
834 fpi_ssm_next_state_delayed (ssm, 10);
835 break;
836
837 case M_LOOP_0_CHECK_ACTION:
838 /* Action not completed */
839 if (self->height > 0)
840 /* Continue loop */
841 fpi_ssm_jump_to_state (ssm, M_LOOP_2_ABORT_PRINT);
842 else
843 /* Error found */
844 fpi_ssm_next_state (ssm);
845 break;
846
847 case M_LOOP_1_GET_STATE:
848 /* Get finger state */
849 vfs_get_finger_state (ssm, dev);
850 break;
851
852 case M_LOOP_1_CHECK_STATE:
853 /* Check finger state */
854 if (vfs_finger_state (self) == VFS_FINGER_PRESENT)
855 {
856 fpi_image_device_report_finger_status (dev, TRUE);
857 fpi_ssm_next_state_delayed (ssm, 250);
858 }
859 else
860 {
861 /* Finger not present */
862 fpi_image_device_report_finger_status (dev, FALSE);
863
864 /* Continue */
865 fpi_ssm_jump_to_state (ssm, M_LOOP_1_SLEEP);
866 }
867 break;
868
869 case M_LOOP_1_GET_PRINT:
870 /* Send get print command to the reader */
871 vfs_get_print (ssm, dev, VFS_BUFFER_HEIGHT, 1);
872 break;
873
874 case M_LOOP_1_LOAD_IMAGE:
875 /* Load image */
876 self->ignore_error = TRUE;
877 vfs_img_load (ssm, dev);
878 break;
879
880 case M_LOOP_1_LOOP:
881 /* Loop */
882 fpi_ssm_jump_to_state (ssm, M_LOOP_1_GET_STATE);
883 break;
884
885 case M_LOOP_1_SLEEP:
886 /* Wait fingerprint scanning */
887 fpi_ssm_next_state_delayed (ssm, 10);
888 break;
889
890 case M_LOOP_2_ABORT_PRINT:
891 /* Abort print command */
892 vfs_abort_print (ssm, dev);
893 break;
894
895 case M_LOOP_2_LOAD_IMAGE:
896 /* Load abort image */
897 self->ignore_error = TRUE;
898 vfs_img_load (ssm, dev);
899 break;
900
901 case M_LOOP_3_GET_PRINT:
902 /* Get empty image */
903 vfs_get_print (ssm, dev, 0x000a, 0);
904 break;
905
906 case M_LOOP_3_LOAD_IMAGE:
907 /* Load abort image */
908 self->ignore_error = TRUE;
909 vfs_img_load (ssm, dev);
910 break;
911
912 case M_LOOP_3_CHECK_IMAGE:
913 if (self->height == 10)
914 {
915 /* Image load correctly, jump to step 0 */
916 self->counter = 0;
917 fpi_ssm_jump_to_state (ssm, M_LOOP_0_GET_PRINT);
918 }
919 else if (self->counter < 10)
920 {
921 /* Wait aborting */
922 self->counter++;
923 fpi_ssm_next_state_delayed (ssm, 100);
924 }
925 else
926 {
927 /* reach max loop counter, return protocol error */
928 fp_err ("waiting abort reach max loop counter");
929 fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
930 }
931 break;
932
933 case M_LOOP_3_LOOP:
934 /* Loop */
935 fpi_ssm_jump_to_state (ssm, M_LOOP_3_GET_PRINT);
936 break;
937 }
938 }
939
940 /* Complete loop sequential state machine */
941 static void
942 m_loop_complete (FpiSsm *ssm, FpDevice *dev, GError *error)
943 {
944 FpDeviceVfs101 *self = FPI_DEVICE_VFS101 (dev);
945
946 /* When the loop completes, we have (successfully) deactivated */
947 if (self->active)
948 fpi_image_device_deactivate_complete (FP_IMAGE_DEVICE (dev),
949 error);
950
951 self->active = FALSE;
952
953 }
954
955 /* Init ssm states */
956 enum {
957 /* Step 0 - Cleanup device buffer */
958 M_INIT_0_RECV_DIRTY,
959 M_INIT_0_ABORT_PRINT,
960 M_INIT_0_LOAD_IMAGE,
961
962 /* Step 1 - Wait aborting */
963 M_INIT_1_GET_PRINT,
964 M_INIT_1_LOAD_IMAGE,
965 M_INIT_1_CHECK_IMAGE,
966 M_INIT_1_LOOP,
967
968 /* Step 2 - Handle unexpected finger presence */
969 M_INIT_2_GET_STATE,
970 M_INIT_2_CHECK_STATE,
971 M_INIT_2_GET_PRINT,
972 M_INIT_2_LOAD_IMAGE,
973 M_INIT_2_LOOP,
974
975 /* Step 3 - Set parameters */
976 M_INIT_3_SET_000E,
977 M_INIT_3_SET_0011,
978 M_INIT_3_SET_0076,
979 M_INIT_3_SET_0078,
980 M_INIT_3_SET_THRESHOLD,
981 M_INIT_3_SET_STATE3_COUNT,
982 M_INIT_3_SET_STATE5_COUNT,
983 M_INIT_3_SET_INFO_CONTRAST,
984 M_INIT_3_SET_INFO_RATE,
985
986 /* Step 4 - Autocalibrate contrast */
987 M_INIT_4_SET_EXPOSURE,
988 M_INIT_4_SET_CONTRAST,
989 M_INIT_4_GET_PRINT,
990 M_INIT_4_LOAD_IMAGE,
991 M_INIT_4_CHECK_CONTRAST,
992
993 /* Step 5 - Set info line parameters */
994 M_INIT_5_SET_EXPOSURE,
995 M_INIT_5_SET_CONTRAST,
996 M_INIT_5_SET_INFO_CONTRAST,
997 M_INIT_5_SET_INFO_RATE,
998
999 /* Number of states */
1000 M_INIT_NUM_STATES,
1001 };
1002
1003 /* Exec init sequential state machine */
1004 static void
1005 m_init_state (FpiSsm *ssm, FpDevice *_dev)
1006 {
1007 FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
1008 FpDeviceVfs101 *self = FPI_DEVICE_VFS101 (_dev);
1009
1010 /* Mark as cancelled when activation collides with deactivation. */
1011 if (self->deactivate)
1012 {
1013 fpi_ssm_mark_failed (ssm,
1014 g_error_new (G_IO_ERROR,
1015 G_IO_ERROR_CANCELLED,
1016 "Initialisation was cancelled"));
1017 return;
1018 }
1019
1020 switch (fpi_ssm_get_cur_state (ssm))
1021 {
1022 case M_INIT_0_RECV_DIRTY:
1023 /* Recv eventually dirty data */
1024 self->ignore_error = TRUE;
1025 async_recv (ssm, dev);
1026 break;
1027
1028 case M_INIT_0_ABORT_PRINT:
1029 /* Abort print command */
1030 vfs_abort_print (ssm, dev);
1031 break;
1032
1033 case M_INIT_0_LOAD_IMAGE:
1034 /* Load abort image */
1035 self->ignore_error = TRUE;
1036 vfs_img_load (ssm, dev);
1037 break;
1038
1039 case M_INIT_1_GET_PRINT:
1040 /* Get empty image */
1041 vfs_get_print (ssm, dev, 0x000a, 0);
1042 break;
1043
1044 case M_INIT_1_LOAD_IMAGE:
1045 /* Load abort image */
1046 self->ignore_error = TRUE;
1047 vfs_img_load (ssm, dev);
1048 break;
1049
1050 case M_INIT_1_CHECK_IMAGE:
1051 if (self->height == 10)
1052 {
1053 /* Image load correctly, jump to step 2 */
1054 self->counter = 0;
1055 fpi_ssm_jump_to_state (ssm, M_INIT_2_GET_STATE);
1056 }
1057 else if (self->counter < 10)
1058 {
1059 /* Wait aborting */
1060 self->counter++;
1061 fpi_ssm_next_state_delayed (ssm, 100);
1062 }
1063 else
1064 {
1065 /* reach max loop counter, return protocol error */
1066 fp_err ("waiting abort reach max loop counter");
1067 fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
1068 }
1069 break;
1070
1071 case M_INIT_1_LOOP:
1072 /* Loop */
1073 fpi_ssm_jump_to_state (ssm, M_INIT_1_GET_PRINT);
1074 break;
1075
1076 case M_INIT_2_GET_STATE:
1077 /* Get finger state */
1078 vfs_get_finger_state (ssm, dev);
1079 break;
1080
1081 case M_INIT_2_CHECK_STATE:
1082 /* Check finger state */
1083 if (vfs_finger_state (self) == VFS_FINGER_PRESENT)
1084 {
1085 /* Wait a bit for finger removal; if it doesn't happen, prompt */
1086 if (self->counter < 2)
1087 {
1088 /* Wait removing finger */
1089 self->counter++;
1090 fpi_ssm_next_state_delayed (ssm, 250);
1091 }
1092 else
1093 {
1094 /* The user should remove their finger from the scanner */
1095 fp_warn ("unexpected finger find, remove finger from the scanner");
1096 fpi_ssm_mark_failed (ssm, fpi_device_retry_new (FP_DEVICE_RETRY_REMOVE_FINGER));
1097 }
1098 }
1099 else
1100 {
1101 /* Finger not present */
1102 if (self->counter == 0)
1103 {
1104 /* Continue */
1105 fpi_ssm_jump_to_state (ssm, M_INIT_3_SET_000E);
1106 }
1107 else
1108 {
1109 /* Finger removed, jump to abort */
1110 self->counter = 0;
1111 fpi_ssm_jump_to_state (ssm, M_INIT_0_ABORT_PRINT);
1112 }
1113 }
1114 break;
1115
1116 case M_INIT_2_GET_PRINT:
1117 /* Send get print command to the reader */
1118 vfs_get_print (ssm, dev, VFS_BUFFER_HEIGHT, 1);
1119 break;
1120
1121 case M_INIT_2_LOAD_IMAGE:
1122 /* Load unexpected image */
1123 self->ignore_error = TRUE;
1124 vfs_img_load (ssm, dev);
1125 break;
1126
1127 case M_INIT_2_LOOP:
1128 /* Loop */
1129 fpi_ssm_jump_to_state (ssm, M_INIT_2_GET_STATE);
1130 break;
1131
1132 case M_INIT_3_SET_000E:
1133 /* Set param 0x000e, required for take image */
1134 vfs_set_param (ssm, dev, VFS_PAR_000E, VFS_VAL_000E);
1135 break;
1136
1137 case M_INIT_3_SET_0011:
1138 /* Set param 0x0011, required for take image */
1139 vfs_set_param (ssm, dev, VFS_PAR_0011, VFS_VAL_0011);
1140 break;
1141
1142 case M_INIT_3_SET_0076:
1143 /* Set param 0x0076, required for use info line */
1144 vfs_set_param (ssm, dev, VFS_PAR_0076, VFS_VAL_0076);
1145 break;
1146
1147 case M_INIT_3_SET_0078:
1148 /* Set param 0x0078, required for use info line */
1149 vfs_set_param (ssm, dev, VFS_PAR_0078, VFS_VAL_0078);
1150 break;
1151
1152 case M_INIT_3_SET_THRESHOLD:
1153 /* Set threshold */
1154 vfs_set_param (ssm, dev, VFS_PAR_THRESHOLD, VFS_VAL_THRESHOLD);
1155 break;
1156
1157 case M_INIT_3_SET_STATE3_COUNT:
1158 /* Set state 3 count */
1159 vfs_set_param (ssm, dev, VFS_PAR_STATE_3, VFS_VAL_STATE_3);
1160 break;
1161
1162 case M_INIT_3_SET_STATE5_COUNT:
1163 /* Set state 5 count */
1164 vfs_set_param (ssm, dev, VFS_PAR_STATE_5, VFS_VAL_STATE_5);
1165 break;
1166
1167 case M_INIT_3_SET_INFO_CONTRAST:
1168 /* Set info line contrast */
1169 vfs_set_param (ssm, dev, VFS_PAR_INFO_CONTRAST, 10);
1170 break;
1171
1172 case M_INIT_3_SET_INFO_RATE:
1173 /* Set info line rate */
1174 vfs_set_param (ssm, dev, VFS_PAR_INFO_RATE, 32);
1175 break;
1176
1177 case M_INIT_4_SET_EXPOSURE:
1178 /* Set exposure level of reader */
1179 vfs_poke (ssm, dev, VFS_REG_IMG_EXPOSURE, 0x4000, 0x02);
1180 self->counter = 1;
1181 break;
1182
1183 case M_INIT_4_SET_CONTRAST:
1184 /* Set contrast level of reader */
1185 vfs_poke (ssm, dev, VFS_REG_IMG_CONTRAST, self->contrast, 0x01);
1186 break;
1187
1188 case M_INIT_4_GET_PRINT:
1189 /* Get empty image */
1190 vfs_get_print (ssm, dev, 0x000a, 0);
1191 break;
1192
1193 case M_INIT_4_LOAD_IMAGE:
1194 /* Load empty image */
1195 vfs_img_load (ssm, dev);
1196 break;
1197
1198 case M_INIT_4_CHECK_CONTRAST:
1199 /* Check contrast */
1200 vfs_check_contrast (self);
1201
1202 if (self->contrast <= 6 || self->counter >= 12)
1203 {
1204 /* End contrast scan, continue */
1205 self->contrast = self->best_contrast;
1206 self->counter = 0;
1207 fp_dbg ("use contrast value = %d", self->contrast);
1208 fpi_ssm_next_state (ssm);
1209 }
1210 else
1211 {
1212 /* Continue contrast scan, loop */
1213 self->contrast--;
1214 self->counter++;
1215 fpi_ssm_jump_to_state (ssm, M_INIT_4_SET_CONTRAST);
1216 }
1217 break;
1218
1219 case M_INIT_5_SET_EXPOSURE:
1220 /* Set exposure level of reader */
1221 vfs_poke (ssm, dev, VFS_REG_IMG_EXPOSURE, VFS_VAL_IMG_EXPOSURE, 0x02);
1222 break;
1223
1224 case M_INIT_5_SET_CONTRAST:
1225 /* Set contrast level of reader */
1226 vfs_poke (ssm, dev, VFS_REG_IMG_CONTRAST, self->contrast, 0x01);
1227 break;
1228
1229 case M_INIT_5_SET_INFO_CONTRAST:
1230 /* Set info line contrast */
1231 vfs_set_param (ssm, dev, VFS_PAR_INFO_CONTRAST, self->contrast);
1232 break;
1233
1234 case M_INIT_5_SET_INFO_RATE:
1235 /* Set info line rate */
1236 vfs_set_param (ssm, dev, VFS_PAR_INFO_RATE, VFS_VAL_INFO_RATE);
1237 break;
1238 }
1239 }
1240
1241 /* Complete init sequential state machine */
1242 static void
1243 m_init_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
1244 {
1245 FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
1246
1247 /* Notify activate complete */
1248 fpi_image_device_activate_complete (dev, error);
1249
1250 if (!error)
1251 {
1252 FpiSsm *ssm_loop;
1253
1254 /* Start loop ssm */
1255 ssm_loop = fpi_ssm_new (FP_DEVICE (dev), m_loop_state, M_LOOP_NUM_STATES);
1256 fpi_ssm_start (ssm_loop, m_loop_complete);
1257 }
1258
1259 /* Free sequential state machine */
1260 }
1261
1262 /* Activate device */
1263 static void
1264 dev_activate (FpImageDevice *dev)
1265 {
1266 FpDeviceVfs101 *self = FPI_DEVICE_VFS101 (dev);
1267 FpiSsm *ssm;
1268
1269 /* Check if already active */
1270 g_assert (!self->active);
1271
1272 /* Set active state */
1273 self->active = TRUE;
1274 self->deactivate = FALSE;
1275
1276 /* Set contrast */
1277 self->contrast = 15;
1278 self->best_clevel = -1;
1279
1280 /* Reset loop counter */
1281 self->counter = 0;
1282
1283 /* Start init ssm */
1284 ssm = fpi_ssm_new (FP_DEVICE (dev), m_init_state, M_INIT_NUM_STATES);
1285 fpi_ssm_start (ssm, m_init_complete);
1286 }
1287
1288 /* Deactivate device */
1289 static void
1290 dev_deactivate (FpImageDevice *dev)
1291 {
1292 FpDeviceVfs101 *self = FPI_DEVICE_VFS101 (dev);
1293
1294 /* Device already deactivated, likely due to an error */
1295 if (!self->active)
1296 {
1297 fpi_image_device_deactivate_complete (dev, NULL);
1298 return;
1299 }
1300
1301 /* Signal deactivation, deactivation will happen from the SSM
1302 * completion handler. */
1303 self->deactivate = TRUE;
1304 }
1305
1306 /* Open device */
1307 static void
1308 dev_open (FpImageDevice *dev)
1309 {
1310 FpDeviceVfs101 *self = FPI_DEVICE_VFS101 (dev);
1311 GError *error = NULL;
1312
1313 /* Claim usb interface */
1314 g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error);
1315
1316 /* Initialize private structure */
1317 self->seqnum = -1;
1318 self->buffer = g_malloc0 (VFS_BUFFER_SIZE);
1319
1320 /* Notify open complete */
1321 fpi_image_device_open_complete (dev, error);
1322 }
1323
1324 /* Close device */
1325 static void
1326 dev_close (FpImageDevice *dev)
1327 {
1328 FpDeviceVfs101 *self = FPI_DEVICE_VFS101 (dev);
1329 GError *error = NULL;
1330
1331 /* Release usb interface */
1332 g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)),
1333 0, 0, &error);
1334
1335 g_clear_pointer (&self->buffer, g_free);
1336
1337 /* Notify close complete */
1338 fpi_image_device_close_complete (dev, error);
1339 }
1340
1341 /* Usb id table of device */
1342 static const FpIdEntry id_table[] = {
1343 { .vid = 0x138a, .pid = 0x0001, },
1344 { .vid = 0, .pid = 0, .driver_data = 0 },
1345 };
1346
1347 static void
1348 fpi_device_vfs101_init (FpDeviceVfs101 *self)
1349 {
1350 }
1351
1352 static void
1353 125 fpi_device_vfs101_class_init (FpDeviceVfs101Class *klass)
1354 {
1355 125 FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
1356 125 FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
1357
1358 125 dev_class->id = "vfs101";
1359 125 dev_class->full_name = "Validity VFS101";
1360 125 dev_class->type = FP_DEVICE_TYPE_USB;
1361 125 dev_class->id_table = id_table;
1362 125 dev_class->scan_type = FP_SCAN_TYPE_SWIPE;
1363
1364 125 img_class->img_open = dev_open;
1365 125 img_class->img_close = dev_close;
1366 125 img_class->activate = dev_activate;
1367 125 img_class->deactivate = dev_deactivate;
1368
1369 125 img_class->bz3_threshold = 24;
1370
1371 125 img_class->img_width = VFS_IMG_WIDTH;
1372 125 img_class->img_height = -1;
1373 }
1374