GCC Code Coverage Report


Directory: ./
File: libfprint/drivers/vfs101.c
Date: 2024-09-16 14:36:32
Exec Total Coverage
Lines: 16 495 3.2%
Functions: 3 30 10.0%
Branches: 4 153 2.6%

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/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 (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 g_error_free (error);
188 fp_dbg ("Ignoring send error: %s", error->message);
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 /* Check difference from byte 4 to byte 5 for verify contrast of image */
712 for (y = 0; y < vdev->height; y++)
713 count = count + vdev->buffer[offset (5, y)] - vdev->buffer[offset (4, y)];
714 count = count / vdev->height;
715
716 if (count < 16)
717 {
718 /* Contrast not valid, retry */
719 vdev->contrast++;
720 return;
721 }
722
723 fp_dbg ("contrast = %d, level = %ld", vdev->contrast, count);
724
725 if (labs (count - VFS_IMG_BEST_CONTRAST) < abs (vdev->best_clevel - VFS_IMG_BEST_CONTRAST))
726 {
727 /* Better contrast found, use it */
728 vdev->best_contrast = vdev->contrast;
729 vdev->best_clevel = count;
730 }
731 }
732
733 /* Loop ssm states */
734 enum {
735 /* Step 0 - Scan finger */
736 M_LOOP_0_GET_PRINT,
737 M_LOOP_0_SLEEP,
738 M_LOOP_0_GET_STATE,
739 M_LOOP_0_LOAD_IMAGE,
740 M_LOOP_0_EXTRACT_IMAGE,
741 M_LOOP_0_CHECK_ACTION,
742
743 /* Step 1 - Scan failed */
744 M_LOOP_1_GET_STATE,
745 M_LOOP_1_CHECK_STATE,
746 M_LOOP_1_GET_PRINT,
747 M_LOOP_1_LOAD_IMAGE,
748 M_LOOP_1_LOOP,
749 M_LOOP_1_SLEEP,
750
751 /* Step 2 - Abort print */
752 M_LOOP_2_ABORT_PRINT,
753 M_LOOP_2_LOAD_IMAGE,
754
755 /* Step 3 - Wait aborting */
756 M_LOOP_3_GET_PRINT,
757 M_LOOP_3_LOAD_IMAGE,
758 M_LOOP_3_CHECK_IMAGE,
759 M_LOOP_3_LOOP,
760
761 /* Number of states */
762 M_LOOP_NUM_STATES,
763 };
764
765 /* Exec loop sequential state machine */
766 static void
767 m_loop_state (FpiSsm *ssm, FpDevice *_dev)
768 {
769 FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
770 FpDeviceVfs101 *self = FPI_DEVICE_VFS101 (_dev);
771
772 /* Complete if deactivation was requested */
773 if (self->deactivate)
774 {
775 fpi_ssm_mark_completed (ssm);
776 return;
777 }
778
779 switch (fpi_ssm_get_cur_state (ssm))
780 {
781 case M_LOOP_0_GET_PRINT:
782 /* Send get print command to the reader */
783 vfs_get_print (ssm, dev, VFS_BUFFER_HEIGHT, 1);
784 break;
785
786 case M_LOOP_0_SLEEP:
787 /* Wait fingerprint scanning */
788 fpi_ssm_next_state_delayed (ssm, 50);
789 break;
790
791 case M_LOOP_0_GET_STATE:
792 /* Get finger state */
793 vfs_get_finger_state (ssm, dev);
794 break;
795
796 case M_LOOP_0_LOAD_IMAGE:
797 /* Check finger state */
798 switch (vfs_finger_state (self))
799 {
800 case VFS_FINGER_EMPTY:
801 fpi_image_device_report_finger_status (dev, FALSE);
802
803 /* Finger isn't present, loop */
804 fpi_ssm_jump_to_state (ssm, M_LOOP_0_SLEEP);
805 break;
806
807 case VFS_FINGER_PRESENT:
808 fpi_image_device_report_finger_status (dev, TRUE);
809
810 /* Load image from reader */
811 self->ignore_error = TRUE;
812 vfs_img_load (ssm, dev);
813 break;
814
815 default:
816 fpi_image_device_report_finger_status (dev, FALSE);
817
818 /* Unknown state */
819 fp_err ("unknown device state 0x%02x",
820 self->buffer[0x0a]);
821 fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
822 break;
823 }
824 break;
825
826 case M_LOOP_0_EXTRACT_IMAGE:
827 /* Fingerprint is loaded, extract image from raw data */
828 img_extract (ssm, dev);
829
830 /* Wait handling image */
831 fpi_ssm_next_state_delayed (ssm, 10);
832 break;
833
834 case M_LOOP_0_CHECK_ACTION:
835 /* Action not completed */
836 if (self->height > 0)
837 /* Continue loop */
838 fpi_ssm_jump_to_state (ssm, M_LOOP_2_ABORT_PRINT);
839 else
840 /* Error found */
841 fpi_ssm_next_state (ssm);
842 break;
843
844 case M_LOOP_1_GET_STATE:
845 /* Get finger state */
846 vfs_get_finger_state (ssm, dev);
847 break;
848
849 case M_LOOP_1_CHECK_STATE:
850 /* Check finger state */
851 if (vfs_finger_state (self) == VFS_FINGER_PRESENT)
852 {
853 fpi_image_device_report_finger_status (dev, TRUE);
854 fpi_ssm_next_state_delayed (ssm, 250);
855 }
856 else
857 {
858 /* Finger not present */
859 fpi_image_device_report_finger_status (dev, FALSE);
860
861 /* Continue */
862 fpi_ssm_jump_to_state (ssm, M_LOOP_1_SLEEP);
863 }
864 break;
865
866 case M_LOOP_1_GET_PRINT:
867 /* Send get print command to the reader */
868 vfs_get_print (ssm, dev, VFS_BUFFER_HEIGHT, 1);
869 break;
870
871 case M_LOOP_1_LOAD_IMAGE:
872 /* Load image */
873 self->ignore_error = TRUE;
874 vfs_img_load (ssm, dev);
875 break;
876
877 case M_LOOP_1_LOOP:
878 /* Loop */
879 fpi_ssm_jump_to_state (ssm, M_LOOP_1_GET_STATE);
880 break;
881
882 case M_LOOP_1_SLEEP:
883 /* Wait fingerprint scanning */
884 fpi_ssm_next_state_delayed (ssm, 10);
885 break;
886
887 case M_LOOP_2_ABORT_PRINT:
888 /* Abort print command */
889 vfs_abort_print (ssm, dev);
890 break;
891
892 case M_LOOP_2_LOAD_IMAGE:
893 /* Load abort image */
894 self->ignore_error = TRUE;
895 vfs_img_load (ssm, dev);
896 break;
897
898 case M_LOOP_3_GET_PRINT:
899 /* Get empty image */
900 vfs_get_print (ssm, dev, 0x000a, 0);
901 break;
902
903 case M_LOOP_3_LOAD_IMAGE:
904 /* Load abort image */
905 self->ignore_error = TRUE;
906 vfs_img_load (ssm, dev);
907 break;
908
909 case M_LOOP_3_CHECK_IMAGE:
910 if (self->height == 10)
911 {
912 /* Image load correctly, jump to step 0 */
913 self->counter = 0;
914 fpi_ssm_jump_to_state (ssm, M_LOOP_0_GET_PRINT);
915 }
916 else if (self->counter < 10)
917 {
918 /* Wait aborting */
919 self->counter++;
920 fpi_ssm_next_state_delayed (ssm, 100);
921 }
922 else
923 {
924 /* reach max loop counter, return protocol error */
925 fp_err ("waiting abort reach max loop counter");
926 fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
927 }
928 break;
929
930 case M_LOOP_3_LOOP:
931 /* Loop */
932 fpi_ssm_jump_to_state (ssm, M_LOOP_3_GET_PRINT);
933 break;
934 }
935 }
936
937 /* Complete loop sequential state machine */
938 static void
939 m_loop_complete (FpiSsm *ssm, FpDevice *dev, GError *error)
940 {
941 FpDeviceVfs101 *self = FPI_DEVICE_VFS101 (dev);
942
943 /* When the loop completes, we have (successfully) deactivated */
944 if (self->active)
945 fpi_image_device_deactivate_complete (FP_IMAGE_DEVICE (dev),
946 error);
947
948 self->active = FALSE;
949
950 }
951
952 /* Init ssm states */
953 enum {
954 /* Step 0 - Cleanup device buffer */
955 M_INIT_0_RECV_DIRTY,
956 M_INIT_0_ABORT_PRINT,
957 M_INIT_0_LOAD_IMAGE,
958
959 /* Step 1 - Wait aborting */
960 M_INIT_1_GET_PRINT,
961 M_INIT_1_LOAD_IMAGE,
962 M_INIT_1_CHECK_IMAGE,
963 M_INIT_1_LOOP,
964
965 /* Step 2 - Handle unexpected finger presence */
966 M_INIT_2_GET_STATE,
967 M_INIT_2_CHECK_STATE,
968 M_INIT_2_GET_PRINT,
969 M_INIT_2_LOAD_IMAGE,
970 M_INIT_2_LOOP,
971
972 /* Step 3 - Set parameters */
973 M_INIT_3_SET_000E,
974 M_INIT_3_SET_0011,
975 M_INIT_3_SET_0076,
976 M_INIT_3_SET_0078,
977 M_INIT_3_SET_THRESHOLD,
978 M_INIT_3_SET_STATE3_COUNT,
979 M_INIT_3_SET_STATE5_COUNT,
980 M_INIT_3_SET_INFO_CONTRAST,
981 M_INIT_3_SET_INFO_RATE,
982
983 /* Step 4 - Autocalibrate contrast */
984 M_INIT_4_SET_EXPOSURE,
985 M_INIT_4_SET_CONTRAST,
986 M_INIT_4_GET_PRINT,
987 M_INIT_4_LOAD_IMAGE,
988 M_INIT_4_CHECK_CONTRAST,
989
990 /* Step 5 - Set info line parameters */
991 M_INIT_5_SET_EXPOSURE,
992 M_INIT_5_SET_CONTRAST,
993 M_INIT_5_SET_INFO_CONTRAST,
994 M_INIT_5_SET_INFO_RATE,
995
996 /* Number of states */
997 M_INIT_NUM_STATES,
998 };
999
1000 /* Exec init sequential state machine */
1001 static void
1002 m_init_state (FpiSsm *ssm, FpDevice *_dev)
1003 {
1004 FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
1005 FpDeviceVfs101 *self = FPI_DEVICE_VFS101 (_dev);
1006
1007 /* Mark as cancelled when activation collides with deactivation. */
1008 if (self->deactivate)
1009 {
1010 fpi_ssm_mark_failed (ssm,
1011 g_error_new (G_IO_ERROR,
1012 G_IO_ERROR_CANCELLED,
1013 "Initialisation was cancelled"));
1014 return;
1015 }
1016
1017 switch (fpi_ssm_get_cur_state (ssm))
1018 {
1019 case M_INIT_0_RECV_DIRTY:
1020 /* Recv eventually dirty data */
1021 self->ignore_error = TRUE;
1022 async_recv (ssm, dev);
1023 break;
1024
1025 case M_INIT_0_ABORT_PRINT:
1026 /* Abort print command */
1027 vfs_abort_print (ssm, dev);
1028 break;
1029
1030 case M_INIT_0_LOAD_IMAGE:
1031 /* Load abort image */
1032 self->ignore_error = TRUE;
1033 vfs_img_load (ssm, dev);
1034 break;
1035
1036 case M_INIT_1_GET_PRINT:
1037 /* Get empty image */
1038 vfs_get_print (ssm, dev, 0x000a, 0);
1039 break;
1040
1041 case M_INIT_1_LOAD_IMAGE:
1042 /* Load abort image */
1043 self->ignore_error = TRUE;
1044 vfs_img_load (ssm, dev);
1045 break;
1046
1047 case M_INIT_1_CHECK_IMAGE:
1048 if (self->height == 10)
1049 {
1050 /* Image load correctly, jump to step 2 */
1051 self->counter = 0;
1052 fpi_ssm_jump_to_state (ssm, M_INIT_2_GET_STATE);
1053 }
1054 else if (self->counter < 10)
1055 {
1056 /* Wait aborting */
1057 self->counter++;
1058 fpi_ssm_next_state_delayed (ssm, 100);
1059 }
1060 else
1061 {
1062 /* reach max loop counter, return protocol error */
1063 fp_err ("waiting abort reach max loop counter");
1064 fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
1065 }
1066 break;
1067
1068 case M_INIT_1_LOOP:
1069 /* Loop */
1070 fpi_ssm_jump_to_state (ssm, M_INIT_1_GET_PRINT);
1071 break;
1072
1073 case M_INIT_2_GET_STATE:
1074 /* Get finger state */
1075 vfs_get_finger_state (ssm, dev);
1076 break;
1077
1078 case M_INIT_2_CHECK_STATE:
1079 /* Check finger state */
1080 if (vfs_finger_state (self) == VFS_FINGER_PRESENT)
1081 {
1082 /* Wait a bit for finger removal; if it doesn't happen, prompt */
1083 if (self->counter < 2)
1084 {
1085 /* Wait removing finger */
1086 self->counter++;
1087 fpi_ssm_next_state_delayed (ssm, 250);
1088 }
1089 else
1090 {
1091 /* The user should remove their finger from the scanner */
1092 fp_warn ("unexpected finger find, remove finger from the scanner");
1093 fpi_ssm_mark_failed (ssm, fpi_device_retry_new (FP_DEVICE_RETRY_REMOVE_FINGER));
1094 }
1095 }
1096 else
1097 {
1098 /* Finger not present */
1099 if (self->counter == 0)
1100 {
1101 /* Continue */
1102 fpi_ssm_jump_to_state (ssm, M_INIT_3_SET_000E);
1103 }
1104 else
1105 {
1106 /* Finger removed, jump to abort */
1107 self->counter = 0;
1108 fpi_ssm_jump_to_state (ssm, M_INIT_0_ABORT_PRINT);
1109 }
1110 }
1111 break;
1112
1113 case M_INIT_2_GET_PRINT:
1114 /* Send get print command to the reader */
1115 vfs_get_print (ssm, dev, VFS_BUFFER_HEIGHT, 1);
1116 break;
1117
1118 case M_INIT_2_LOAD_IMAGE:
1119 /* Load unexpected image */
1120 self->ignore_error = TRUE;
1121 vfs_img_load (ssm, dev);
1122 break;
1123
1124 case M_INIT_2_LOOP:
1125 /* Loop */
1126 fpi_ssm_jump_to_state (ssm, M_INIT_2_GET_STATE);
1127 break;
1128
1129 case M_INIT_3_SET_000E:
1130 /* Set param 0x000e, required for take image */
1131 vfs_set_param (ssm, dev, VFS_PAR_000E, VFS_VAL_000E);
1132 break;
1133
1134 case M_INIT_3_SET_0011:
1135 /* Set param 0x0011, required for take image */
1136 vfs_set_param (ssm, dev, VFS_PAR_0011, VFS_VAL_0011);
1137 break;
1138
1139 case M_INIT_3_SET_0076:
1140 /* Set param 0x0076, required for use info line */
1141 vfs_set_param (ssm, dev, VFS_PAR_0076, VFS_VAL_0076);
1142 break;
1143
1144 case M_INIT_3_SET_0078:
1145 /* Set param 0x0078, required for use info line */
1146 vfs_set_param (ssm, dev, VFS_PAR_0078, VFS_VAL_0078);
1147 break;
1148
1149 case M_INIT_3_SET_THRESHOLD:
1150 /* Set threshold */
1151 vfs_set_param (ssm, dev, VFS_PAR_THRESHOLD, VFS_VAL_THRESHOLD);
1152 break;
1153
1154 case M_INIT_3_SET_STATE3_COUNT:
1155 /* Set state 3 count */
1156 vfs_set_param (ssm, dev, VFS_PAR_STATE_3, VFS_VAL_STATE_3);
1157 break;
1158
1159 case M_INIT_3_SET_STATE5_COUNT:
1160 /* Set state 5 count */
1161 vfs_set_param (ssm, dev, VFS_PAR_STATE_5, VFS_VAL_STATE_5);
1162 break;
1163
1164 case M_INIT_3_SET_INFO_CONTRAST:
1165 /* Set info line contrast */
1166 vfs_set_param (ssm, dev, VFS_PAR_INFO_CONTRAST, 10);
1167 break;
1168
1169 case M_INIT_3_SET_INFO_RATE:
1170 /* Set info line rate */
1171 vfs_set_param (ssm, dev, VFS_PAR_INFO_RATE, 32);
1172 break;
1173
1174 case M_INIT_4_SET_EXPOSURE:
1175 /* Set exposure level of reader */
1176 vfs_poke (ssm, dev, VFS_REG_IMG_EXPOSURE, 0x4000, 0x02);
1177 self->counter = 1;
1178 break;
1179
1180 case M_INIT_4_SET_CONTRAST:
1181 /* Set contrast level of reader */
1182 vfs_poke (ssm, dev, VFS_REG_IMG_CONTRAST, self->contrast, 0x01);
1183 break;
1184
1185 case M_INIT_4_GET_PRINT:
1186 /* Get empty image */
1187 vfs_get_print (ssm, dev, 0x000a, 0);
1188 break;
1189
1190 case M_INIT_4_LOAD_IMAGE:
1191 /* Load empty image */
1192 vfs_img_load (ssm, dev);
1193 break;
1194
1195 case M_INIT_4_CHECK_CONTRAST:
1196 /* Check contrast */
1197 vfs_check_contrast (self);
1198
1199 if (self->contrast <= 6 || self->counter >= 12)
1200 {
1201 /* End contrast scan, continue */
1202 self->contrast = self->best_contrast;
1203 self->counter = 0;
1204 fp_dbg ("use contrast value = %d", self->contrast);
1205 fpi_ssm_next_state (ssm);
1206 }
1207 else
1208 {
1209 /* Continue contrast scan, loop */
1210 self->contrast--;
1211 self->counter++;
1212 fpi_ssm_jump_to_state (ssm, M_INIT_4_SET_CONTRAST);
1213 }
1214 break;
1215
1216 case M_INIT_5_SET_EXPOSURE:
1217 /* Set exposure level of reader */
1218 vfs_poke (ssm, dev, VFS_REG_IMG_EXPOSURE, VFS_VAL_IMG_EXPOSURE, 0x02);
1219 break;
1220
1221 case M_INIT_5_SET_CONTRAST:
1222 /* Set contrast level of reader */
1223 vfs_poke (ssm, dev, VFS_REG_IMG_CONTRAST, self->contrast, 0x01);
1224 break;
1225
1226 case M_INIT_5_SET_INFO_CONTRAST:
1227 /* Set info line contrast */
1228 vfs_set_param (ssm, dev, VFS_PAR_INFO_CONTRAST, self->contrast);
1229 break;
1230
1231 case M_INIT_5_SET_INFO_RATE:
1232 /* Set info line rate */
1233 vfs_set_param (ssm, dev, VFS_PAR_INFO_RATE, VFS_VAL_INFO_RATE);
1234 break;
1235 }
1236 }
1237
1238 /* Complete init sequential state machine */
1239 static void
1240 m_init_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
1241 {
1242 FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
1243
1244 /* Notify activate complete */
1245 fpi_image_device_activate_complete (dev, error);
1246
1247 if (!error)
1248 {
1249 FpiSsm *ssm_loop;
1250
1251 /* Start loop ssm */
1252 ssm_loop = fpi_ssm_new (FP_DEVICE (dev), m_loop_state, M_LOOP_NUM_STATES);
1253 fpi_ssm_start (ssm_loop, m_loop_complete);
1254 }
1255
1256 /* Free sequential state machine */
1257 }
1258
1259 /* Activate device */
1260 static void
1261 dev_activate (FpImageDevice *dev)
1262 {
1263 FpDeviceVfs101 *self = FPI_DEVICE_VFS101 (dev);
1264 FpiSsm *ssm;
1265
1266 /* Check if already active */
1267 g_assert (!self->active);
1268
1269 /* Set active state */
1270 self->active = TRUE;
1271 self->deactivate = FALSE;
1272
1273 /* Set contrast */
1274 self->contrast = 15;
1275 self->best_clevel = -1;
1276
1277 /* Reset loop counter */
1278 self->counter = 0;
1279
1280 /* Start init ssm */
1281 ssm = fpi_ssm_new (FP_DEVICE (dev), m_init_state, M_INIT_NUM_STATES);
1282 fpi_ssm_start (ssm, m_init_complete);
1283 }
1284
1285 /* Deactivate device */
1286 static void
1287 dev_deactivate (FpImageDevice *dev)
1288 {
1289 FpDeviceVfs101 *self = FPI_DEVICE_VFS101 (dev);
1290
1291 /* Device already deactivated, likely due to an error */
1292 if (!self->active)
1293 {
1294 fpi_image_device_deactivate_complete (dev, NULL);
1295 return;
1296 }
1297
1298 /* Signal deactivation, deactivation will happen from the SSM
1299 * completion handler. */
1300 self->deactivate = TRUE;
1301 }
1302
1303 /* Open device */
1304 static void
1305 dev_open (FpImageDevice *dev)
1306 {
1307 FpDeviceVfs101 *self = FPI_DEVICE_VFS101 (dev);
1308 GError *error = NULL;
1309
1310 /* Claim usb interface */
1311 g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error);
1312
1313 /* Initialize private structure */
1314 self->seqnum = -1;
1315 self->buffer = g_malloc0 (VFS_BUFFER_SIZE);
1316
1317 /* Notify open complete */
1318 fpi_image_device_open_complete (dev, error);
1319 }
1320
1321 /* Close device */
1322 static void
1323 dev_close (FpImageDevice *dev)
1324 {
1325 FpDeviceVfs101 *self = FPI_DEVICE_VFS101 (dev);
1326 GError *error = NULL;
1327
1328 /* Release usb interface */
1329 g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)),
1330 0, 0, &error);
1331
1332 g_clear_pointer (&self->buffer, g_free);
1333
1334 /* Notify close complete */
1335 fpi_image_device_close_complete (dev, error);
1336 }
1337
1338 /* Usb id table of device */
1339 static const FpIdEntry id_table[] = {
1340 { .vid = 0x138a, .pid = 0x0001, },
1341 { .vid = 0, .pid = 0, .driver_data = 0 },
1342 };
1343
1344 static void
1345 fpi_device_vfs101_init (FpDeviceVfs101 *self)
1346 {
1347 }
1348
1349 static void
1350 120 fpi_device_vfs101_class_init (FpDeviceVfs101Class *klass)
1351 {
1352 120 FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
1353 120 FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
1354
1355 120 dev_class->id = "vfs101";
1356 120 dev_class->full_name = "Validity VFS101";
1357 120 dev_class->type = FP_DEVICE_TYPE_USB;
1358 120 dev_class->id_table = id_table;
1359 120 dev_class->scan_type = FP_SCAN_TYPE_SWIPE;
1360
1361 120 img_class->img_open = dev_open;
1362 120 img_class->img_close = dev_close;
1363 120 img_class->activate = dev_activate;
1364 120 img_class->deactivate = dev_deactivate;
1365
1366 120 img_class->bz3_threshold = 24;
1367
1368 120 img_class->img_width = VFS_IMG_WIDTH;
1369 120 img_class->img_height = -1;
1370 }
1371