GCC Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 86.4% 386 / 0 / 447
Functions: 97.1% 34 / 0 / 35
Branches: 62.3% 94 / 0 / 151

libfprint/drivers/elan.c
Line Branch Exec Source
1 /*
2 * Elan driver for libfprint
3 *
4 * Copyright (C) 2017 Igor Filatov <ia.filatov@gmail.com>
5 * Copyright (C) 2018 Sébastien Béchet <sebastien.bechet@osinix.com >
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 /*
23 * The algorithm which libfprint uses to match fingerprints doesn't like small
24 * images like the ones these drivers produce. There's just not enough minutiae
25 * (recognizable print-specific points) on them for a reliable match. This means
26 * that unless another matching algo is found/implemented, these readers will
27 * not work as good with libfprint as they do with vendor drivers.
28 *
29 * To get bigger images the driver expects you to swipe the finger over the
30 * reader. This works quite well for readers with a rectangular 144x64 sensor.
31 * Worse than real swipe readers but good enough for day-to-day use. It needs
32 * a steady and relatively slow swipe. There are also square 96x96 sensors and
33 * I don't know whether they are in fact usable or not because I don't have one.
34 * I imagine they'd be less reliable because the resulting image is even
35 * smaller. If they can't be made usable with libfprint, I might end up dropping
36 * them because it's better than saying they work when they don't.
37 */
38
39 #define FP_COMPONENT "elan"
40
41 #include "drivers_api.h"
42 #include "elan.h"
43
44 static unsigned char
45 300476160 elan_get_pixel (struct fpi_frame_asmbl_ctx *ctx,
46 struct fpi_frame *frame, unsigned int x,
47 unsigned int y)
48 {
49 300476160 return frame->data[x + y * ctx->frame_width];
50 }
51
52 static struct fpi_frame_asmbl_ctx assembling_ctx = {
53 .frame_width = 0,
54 .frame_height = 0,
55 .image_width = 0,
56 .get_pixel = elan_get_pixel,
57 };
58
59 struct _FpiDeviceElan
60 {
61 FpImageDevice parent;
62
63 /* device config */
64 unsigned short dev_type;
65 unsigned short fw_ver;
66 void (*process_frame) (unsigned short *raw_frame,
67 GSList ** frames);
68 /* end device config */
69
70 /* commands */
71 const struct elan_cmd *cmd;
72 int cmd_timeout;
73 /* end commands */
74
75 /* state */
76 gboolean active;
77 gboolean deactivating;
78 unsigned char *last_read;
79 unsigned char calib_atts_left;
80 unsigned char calib_status;
81 unsigned short *background;
82 unsigned char frame_width;
83 unsigned char frame_height;
84 unsigned char raw_frame_height;
85 int num_frames;
86 GSList *frames;
87 /* end state */
88 };
89
4/6
fpi_device_elan_class_intern_init:
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 127 times.
fpi_device_elan_get_type:
✓ Branch 2 → 3 taken 127 times.
✓ Branch 2 → 7 taken 24 times.
✓ Branch 4 → 5 taken 127 times.
✗ Branch 4 → 7 not taken.
405 G_DEFINE_TYPE (FpiDeviceElan, fpi_device_elan, FP_TYPE_IMAGE_DEVICE);
90
91 static int
92 1868747 cmp_short (const void *a, const void *b)
93 {
94 1868747 return (int) (*(short *) a - *(short *) b);
95 }
96
97 static void
98 10 elan_dev_reset_state (FpiDeviceElan *elandev)
99 {
100 10 G_DEBUG_HERE ();
101
102 10 elandev->cmd = NULL;
103 10 elandev->cmd_timeout = ELAN_CMD_TIMEOUT;
104
105 10 elandev->calib_status = 0;
106
107 10 g_free (elandev->last_read);
108 10 elandev->last_read = NULL;
109
110 10 g_slist_free_full (elandev->frames, g_free);
111 10 elandev->frames = NULL;
112 10 elandev->num_frames = 0;
113 10 }
114
115 static void
116 31 elan_save_frame (FpiDeviceElan *self, unsigned short *frame)
117 {
118 31 G_DEBUG_HERE ();
119
120 /* so far 3 types of readers by sensor dimensions and orientation have been
121 * seen in the wild:
122 * 1. 144x64. Raw images are in portrait orientation while readers themselves
123 * are placed (e.g. built into a touchpad) in landscape orientation. These
124 * need to be rotated before assembling.
125 * 2. 96x96 rotated. Like the first type but square. Likewise, need to be
126 * rotated before assembling.
127 * 3. 96x96 normal. Square and need NOT be rotated. So far there's only been
128 * 1 report of a 0c03 of this type. Hopefully this type can be identified
129 * by device id (and manufacturers don't just install the readers as they
130 * please).
131 * we also discard stripes of 'frame_margin' from bottom and top because
132 * assembling works bad for tall frames */
133
134 31 unsigned char frame_width = self->frame_width;
135 31 unsigned char frame_height = self->frame_height;
136 31 unsigned char raw_height = self->raw_frame_height;
137 31 unsigned char frame_margin = (raw_height - self->frame_height) / 2;
138 31 int frame_idx, raw_idx;
139
140
2/2
✓ Branch 11 → 12 taken 1550 times.
✓ Branch 11 → 13 taken 31 times.
1581 for (int y = 0; y < frame_height; y++)
141
2/2
✓ Branch 9 → 5 taken 223200 times.
✓ Branch 9 → 10 taken 1550 times.
224750 for (int x = 0; x < frame_width; x++)
142 {
143
1/2
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 223200 times.
223200 if (self->dev_type & ELAN_NOT_ROTATED)
144 raw_idx = x + (y + frame_margin) * frame_width;
145 else
146 223200 raw_idx = frame_margin + y + x * raw_height;
147 223200 frame_idx = x + y * frame_width;
148 223200 frame[frame_idx] =
149 223200 GUINT16_FROM_LE (((unsigned short *) self->last_read)[raw_idx]);
150 }
151 31 }
152
153 static void
154 3 elan_save_background (FpiDeviceElan *elandev)
155 {
156 3 G_DEBUG_HERE ();
157
158 3 g_free (elandev->background);
159 6 elandev->background =
160 3 g_malloc (elandev->frame_width * elandev->frame_height *
161 sizeof (short));
162 3 elan_save_frame (elandev, elandev->background);
163 3 }
164
165 /* save a frame as part of the fingerprint image
166 * background needs to have been captured for this routine to work
167 * Elantech recommends 2-step non-linear normalization in order to reduce
168 * 2^14 ADC resolution to 2^8 image:
169 *
170 * 1. background is subtracted (done here)
171 *
172 * 2. pixels are grouped in 3 groups by intensity and each group is mapped
173 * separately onto the normalized frame (done in elan_process_frame_*)
174 * ==== 16383 ____> ======== 255
175 * /
176 * ----- lvl3 __/
177 * 35% pixels
178 *
179 * ----- lvl2 --------> ======== 156
180 *
181 * 30% pixels
182 * ----- lvl1 --------> ======== 99
183 *
184 * 35% pixels
185 * ----- lvl0 __
186 * \
187 * ======== 0 \____> ======== 0
188 *
189 * For some devices we don't do 2. but instead do a simple linear mapping
190 * because it seems to produce better results (or at least as good):
191 * ==== 16383 ___> ======== 255
192 * /
193 * ------ max __/
194 *
195 *
196 * ------ min __
197 * \
198 * ======== 0 \___> ======== 0
199 */
200 static int
201 28 elan_save_img_frame (FpiDeviceElan *elandev)
202 {
203 28 G_DEBUG_HERE ();
204
205 28 unsigned int frame_size = elandev->frame_width * elandev->frame_height;
206 28 unsigned short *frame = g_malloc (frame_size * sizeof (short));
207
208 28 elan_save_frame (elandev, frame);
209 28 unsigned int sum = 0;
210
211
2/2
✓ Branch 10 → 7 taken 201600 times.
✓ Branch 10 → 11 taken 28 times.
201656 for (int i = 0; i < frame_size; i++)
212 {
213
2/2
✓ Branch 7 → 8 taken 198563 times.
✓ Branch 7 → 9 taken 3037 times.
201600 if (elandev->background[i] > frame[i])
214 frame[i] = 0;
215 else
216 198563 frame[i] -= elandev->background[i];
217 201600 sum += frame[i];
218 }
219
220
1/2
✗ Branch 11 → 12 not taken.
✓ Branch 11 → 15 taken 28 times.
28 if (sum == 0)
221 {
222 fp_dbg
223 ("frame darker than background; finger present during calibration?");
224 g_free (frame);
225 return -1;
226 }
227
228 28 elandev->frames = g_slist_prepend (elandev->frames, frame);
229 28 elandev->num_frames += 1;
230 28 return 0;
231 }
232
233 static void
234 elan_process_frame_linear (unsigned short *raw_frame,
235 GSList ** frames)
236 {
237 unsigned int frame_size =
238 assembling_ctx.frame_width * assembling_ctx.frame_height;
239 struct fpi_frame *frame =
240 g_malloc (frame_size + sizeof (struct fpi_frame));
241
242 G_DEBUG_HERE ();
243
244 unsigned short min = 0xffff, max = 0;
245
246 for (int i = 0; i < frame_size; i++)
247 {
248 if (raw_frame[i] < min)
249 min = raw_frame[i];
250 if (raw_frame[i] > max)
251 max = raw_frame[i];
252 }
253
254 if (max == min)
255 {
256 memset (frame->data, 0, frame_size);
257 *frames = g_slist_prepend (*frames, frame);
258 g_return_if_reached ();
259 }
260
261 unsigned short px;
262
263 for (int i = 0; i < frame_size; i++)
264 {
265 px = raw_frame[i];
266 px = (px - min) * 0xff / (max - min);
267 frame->data[i] = (unsigned char) px;
268 }
269
270 *frames = g_slist_prepend (*frames, frame);
271 }
272
273 static void
274 24 elan_process_frame_thirds (unsigned short *raw_frame,
275 GSList ** frames)
276 {
277 24 G_DEBUG_HERE ();
278
279 24 unsigned int frame_size =
280 24 assembling_ctx.frame_width * assembling_ctx.frame_height;
281 24 struct fpi_frame *frame =
282 24 g_malloc (frame_size + sizeof (struct fpi_frame));
283
284 24 unsigned short lvl0, lvl1, lvl2, lvl3;
285 24 unsigned short *sorted = g_malloc (frame_size * sizeof (short));
286
287 24 memcpy (sorted, raw_frame, frame_size * sizeof (short));
288 24 qsort (sorted, frame_size, sizeof (short), cmp_short);
289 24 lvl0 = sorted[0];
290 24 lvl1 = sorted[frame_size * 3 / 10];
291 24 lvl2 = sorted[frame_size * 65 / 100];
292 24 lvl3 = sorted[frame_size - 1];
293 24 g_free (sorted);
294
295 /* Ensure levels are strictly monotonic to prevent division by zero */
296 24 lvl1 = MAX (lvl1, lvl0 + 1);
297 24 lvl2 = MAX (lvl2, lvl1 + 1);
298 24 lvl3 = MAX (lvl3, lvl2 + 1);
299
300 24 unsigned short px;
301
302
2/2
✓ Branch 15 → 9 taken 172800 times.
✓ Branch 15 → 16 taken 24 times.
172824 for (int i = 0; i < frame_size; i++)
303 {
304 172800 px = raw_frame[i];
305
2/2
✓ Branch 9 → 10 taken 51794 times.
✓ Branch 9 → 11 taken 121006 times.
172800 if (lvl0 <= px && px < lvl1)
306 51794 px = (px - lvl0) * 99 / (lvl1 - lvl0);
307
2/2
✓ Branch 11 → 12 taken 60488 times.
✓ Branch 11 → 13 taken 60518 times.
121006 else if (lvl1 <= px && px < lvl2)
308 60488 px = 99 + ((px - lvl1) * 56 / (lvl2 - lvl1));
309 else // (lvl2 <= px && px <= lvl3)
310 60518 px = 155 + ((px - lvl2) * 100 / (lvl3 - lvl2));
311 172800 frame->data[i] = (unsigned char) px;
312 }
313
314 24 *frames = g_slist_prepend (*frames, frame);
315 24 }
316
317 static void
318 2 elan_submit_image (FpImageDevice *dev)
319 {
320 2 FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
321 2 GSList *raw_frames;
322 2 GSList *frames = NULL;
323 2 FpImage *img;
324
325 2 G_DEBUG_HERE ();
326
327 2 raw_frames = g_slist_nth (self->frames, ELAN_SKIP_LAST_FRAMES);
328
329 2 assembling_ctx.frame_width = self->frame_width;
330 2 assembling_ctx.frame_height = self->frame_height;
331 2 assembling_ctx.image_width = self->frame_width * 3 / 2;
332 2 g_slist_foreach (raw_frames, (GFunc) self->process_frame, &frames);
333 2 fpi_do_movement_estimation (&assembling_ctx, frames);
334 2 img = fpi_assemble_frames (&assembling_ctx, frames);
335 2 img->flags |= FPI_IMAGE_PARTIAL;
336
337 2 g_slist_free_full (frames, g_free);
338
339 2 fpi_image_device_image_captured (dev, img);
340 2 }
341
342 static void
343 80 elan_cmd_done (FpiSsm *ssm)
344 {
345 80 G_DEBUG_HERE ();
346 80 fpi_ssm_next_state (ssm);
347 80 }
348
349 static void
350 152 elan_cmd_cb (FpiUsbTransfer *transfer, FpDevice *dev,
351 gpointer user_data, GError *error)
352 {
353 152 FpiSsm *ssm = transfer->ssm;
354 152 FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
355
356 152 G_DEBUG_HERE ();
357
358
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 7 taken 152 times.
152 if (error)
359 {
360 /* XXX: In the cancellation case we used to not
361 * mark the SSM as failed?! */
362 fpi_ssm_mark_failed (transfer->ssm, error);
363 return;
364 }
365
366 /* XXX: We used to reset the device in error cases! */
367
2/2
✓ Branch 7 → 8 taken 74 times.
✓ Branch 7 → 10 taken 78 times.
152 if (transfer->endpoint & FPI_USB_ENDPOINT_IN)
368 {
369 /* just finished receiving */
370 74 self->last_read = g_memdup2 (transfer->buffer, transfer->actual_length);
371 74 elan_cmd_done (ssm);
372 }
373 else
374 {
375 /* just finished sending */
376 78 G_DEBUG_HERE ();
377 78 elan_cmd_read (ssm, dev);
378 }
379 }
380
381 static void
382 78 elan_cmd_read (FpiSsm *ssm, FpDevice *dev)
383 {
384 78 FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
385 78 FpiUsbTransfer *transfer;
386 78 GCancellable *cancellable = NULL;
387 78 int response_len = self->cmd->response_len;
388
389 78 G_DEBUG_HERE ();
390
391
2/2
✓ Branch 4 → 5 taken 4 times.
✓ Branch 4 → 8 taken 74 times.
78 if (self->cmd->response_len == ELAN_CMD_SKIP_READ)
392 {
393 4 fp_dbg ("skipping read, not expecting anything");
394 4 elan_cmd_done (ssm);
395 4 return;
396 }
397
398
1/2
✓ Branch 8 → 9 taken 74 times.
✗ Branch 8 → 10 not taken.
74 if (self->dev_type == ELAN_0C42)
399 {
400 /* ELAN_0C42 sends an extra byte in one byte responses */
401 if (self->cmd->response_len == 1)
402 74 response_len = 2;
403 }
404
405
2/2
✓ Branch 11 → 12 taken 31 times.
✓ Branch 11 → 13 taken 43 times.
74 if (self->cmd->cmd == get_image_cmd.cmd)
406 /* raw data has 2-byte "pixels" and the frame is vertical */
407 31 response_len =
408 31 self->raw_frame_height * self->frame_width * 2;
409
410
2/2
✓ Branch 13 → 14 taken 68 times.
✓ Branch 13 → 15 taken 6 times.
74 g_clear_pointer (&self->last_read, g_free);
411
412 74 transfer = fpi_usb_transfer_new (dev);
413 74 transfer->ssm = ssm;
414 74 transfer->short_is_error = TRUE;
415
416 74 fpi_usb_transfer_fill_bulk (transfer,
417 74 self->cmd->response_in,
418 response_len);
419
420
1/2
✓ Branch 17 → 18 taken 74 times.
✗ Branch 17 → 19 not taken.
74 if (!self->cmd->never_cancel)
421 74 cancellable = fpi_device_get_cancellable (dev);
422
423 74 fpi_usb_transfer_submit (transfer, self->cmd_timeout, cancellable, elan_cmd_cb, NULL);
424 }
425
426 static void
427 80 elan_run_cmd (FpiSsm *ssm,
428 FpDevice *dev,
429 const struct elan_cmd *cmd,
430 int cmd_timeout)
431 {
432 80 FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
433 80 FpiUsbTransfer *transfer;
434 80 GCancellable *cancellable = NULL;
435
436 80 self->cmd = cmd;
437
2/2
✓ Branch 2 → 3 taken 50 times.
✓ Branch 2 → 4 taken 30 times.
80 if (cmd_timeout != -1)
438 50 self->cmd_timeout = cmd_timeout;
439
440
3/4
✓ Branch 4 → 5 taken 2 times.
✓ Branch 4 → 9 taken 78 times.
✓ Branch 5 → 6 taken 2 times.
✗ Branch 5 → 9 not taken.
80 if (cmd->devices != ELAN_ALL_DEV && !(cmd->devices & self->dev_type))
441 {
442 2 fp_dbg ("skipping command 0x%x 0x%x for this device (for devices 0x%x but device is 0x%x)",
443 cmd->cmd[0], cmd->cmd[1], cmd->devices, self->dev_type);
444 2 elan_cmd_done (ssm);
445 2 return;
446 }
447
448 78 transfer = fpi_usb_transfer_new (dev);
449 78 transfer->ssm = ssm;
450 78 transfer->short_is_error = TRUE;
451
452 78 fpi_usb_transfer_fill_bulk_full (transfer,
453 ELAN_EP_CMD_OUT,
454 78 (guint8 *) cmd->cmd,
455 ELAN_CMD_LEN,
456 NULL);
457
458
2/2
✓ Branch 11 → 12 taken 76 times.
✓ Branch 11 → 13 taken 2 times.
78 if (!self->cmd->never_cancel)
459 76 cancellable = fpi_device_get_cancellable (dev);
460
461 78 fpi_usb_transfer_submit (transfer,
462 78 self->cmd_timeout,
463 cancellable,
464 elan_cmd_cb,
465 NULL);
466 }
467
468 enum stop_capture_states {
469 STOP_CAPTURE,
470 STOP_CAPTURE_NUM_STATES,
471 };
472
473 static void
474 2 stop_capture_run_state (FpiSsm *ssm, FpDevice *dev)
475 {
476 2 G_DEBUG_HERE ();
477
478
1/2
✓ Branch 5 → 6 taken 2 times.
✗ Branch 5 → 8 not taken.
2 switch (fpi_ssm_get_cur_state (ssm))
479 {
480 2 case STOP_CAPTURE:
481 2 elan_run_cmd (ssm, dev, &stop_cmd,
482 ELAN_CMD_TIMEOUT);
483 2 break;
484 }
485 2 }
486
487 static void
488 2 stop_capture_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
489 {
490 2 FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
491 2 FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
492
493 2 G_DEBUG_HERE ();
494
495
496 /* The device is inactive at this point. */
497 2 self->active = FALSE;
498
499
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 7 taken 2 times.
2 if (self->deactivating)
500 {
501 /* Simply complete the pending deactivation. */
502 self->deactivating = FALSE;
503 fpi_image_device_deactivate_complete (dev, error);
504 return;
505 }
506
507
1/2
✓ Branch 7 → 8 taken 2 times.
✗ Branch 7 → 9 not taken.
2 if (!error)
508 2 fpi_image_device_report_finger_status (dev, FALSE);
509 else
510 /* NOTE: We cannot get a cancellation error here. */
511 fpi_image_device_session_error (dev, error);
512 }
513
514 static void
515 2 elan_stop_capture (FpiDeviceElan *self)
516 {
517 2 G_DEBUG_HERE ();
518
519 2 elan_dev_reset_state (self);
520
521 2 FpiSsm *ssm =
522 2 fpi_ssm_new (FP_DEVICE (self), stop_capture_run_state, STOP_CAPTURE_NUM_STATES);
523
524 2 fpi_ssm_start (ssm, stop_capture_complete);
525 2 }
526
527 enum capture_states {
528 CAPTURE_LED_ON,
529 CAPTURE_WAIT_FINGER,
530 CAPTURE_READ_DATA,
531 CAPTURE_CHECK_ENOUGH_FRAMES,
532 CAPTURE_NUM_STATES,
533 };
534
535 static void
536 90 capture_run_state (FpiSsm *ssm, FpDevice *dev)
537 {
538 90 FpImageDevice *idev = FP_IMAGE_DEVICE (dev);
539 90 FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
540 90 int r;
541
542
4/5
✓ Branch 3 → 4 taken 2 times.
✓ Branch 3 → 6 taken 30 times.
✓ Branch 3 → 8 taken 30 times.
✓ Branch 3 → 21 taken 28 times.
✗ Branch 3 → 28 not taken.
90 switch (fpi_ssm_get_cur_state (ssm))
543 {
544 2 case CAPTURE_LED_ON:
545 2 elan_run_cmd (ssm, dev, &led_on_cmd, ELAN_CMD_TIMEOUT);
546 2 break;
547
548 30 case CAPTURE_WAIT_FINGER:
549 30 elan_run_cmd (ssm, dev, &pre_scan_cmd, -1);
550 30 break;
551
552 30 case CAPTURE_READ_DATA:
553 /* 0x55 - finger present
554 * 0xff - device not calibrated (probably) */
555
3/4
✓ Branch 8 → 9 taken 28 times.
✓ Branch 8 → 12 taken 2 times.
✓ Branch 9 → 10 taken 28 times.
✗ Branch 9 → 12 not taken.
30 if (self->last_read && self->last_read[0] == 0x55)
556 {
557 28 fpi_image_device_report_finger_status (idev, TRUE);
558 28 elan_run_cmd (ssm, dev, &get_image_cmd, ELAN_CMD_TIMEOUT);
559 }
560
1/4
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 16 taken 2 times.
✗ Branch 13 → 14 not taken.
✗ Branch 13 → 16 not taken.
2 else if (self->dev_type == ELAN_0C58 && self->last_read &&
561 (self->last_read[0] == 0x00 || self->last_read[0] == 0xaf))
562 {
563 /* 0x00 - not ready
564 * 0xaf - finger removed or sensor busy (seen on 0x0c58) */
565 fpi_ssm_jump_to_state_delayed (ssm, CAPTURE_WAIT_FINGER, 10);
566 }
567 else
568 {
569 /* XXX: The timeout is emulated incorrectly, resulting in a zero byte read. */
570
1/2
✗ Branch 17 → 18 not taken.
✓ Branch 17 → 20 taken 2 times.
2 if (fpi_device_emulation_mode_enabled (FP_DEVICE (self)))
571 2 fpi_ssm_mark_completed (ssm);
572 else
573 fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
574 }
575 break;
576
577 28 case CAPTURE_CHECK_ENOUGH_FRAMES:
578 28 r = elan_save_img_frame (self);
579
1/2
✗ Branch 22 → 23 not taken.
✓ Branch 22 → 25 taken 28 times.
28 if (r < 0)
580 {
581 fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
582 }
583
1/2
✓ Branch 25 → 26 taken 28 times.
✗ Branch 25 → 27 not taken.
28 else if (self->num_frames < ELAN_MAX_FRAMES)
584 {
585 /* quickly stop if finger is removed */
586 28 self->cmd_timeout = ELAN_FINGER_TIMEOUT;
587 28 fpi_ssm_jump_to_state (ssm, CAPTURE_WAIT_FINGER);
588 }
589 else
590 {
591 fpi_ssm_next_state (ssm);
592 }
593 break;
594 }
595 90 }
596
597 static void
598 2 capture_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
599 {
600 2 FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
601 2 FpiDeviceElan *self = FPI_DEVICE_ELAN (_dev);
602
603 2 G_DEBUG_HERE ();
604
605 /* either max frames captured or timed out waiting for the next frame */
606
1/4
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 10 taken 2 times.
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 15 not taken.
2 if (!error ||
607 (g_error_matches (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_TIMED_OUT) &&
608 fpi_ssm_get_cur_state (ssm) == CAPTURE_WAIT_FINGER))
609 {
610
1/2
✓ Branch 10 → 11 taken 2 times.
✗ Branch 10 → 12 not taken.
2 if (self->num_frames >= ELAN_MIN_FRAMES)
611 {
612 2 elan_submit_image (dev);
613 }
614 else
615 {
616 fp_dbg ("swipe too short: want >= %d frames, got %d",
617 ELAN_MIN_FRAMES, self->num_frames);
618 fpi_image_device_retry_scan (dev, FP_DEVICE_RETRY_TOO_SHORT);
619 }
620 2 g_clear_error (&error);
621 }
622 else
623 {
624 fpi_image_device_session_error (dev, error);
625 }
626
627 /* Note: We always stop capturing even if that may not be needed always.
628 * Doing this between captures appears to make it at least less likely for
629 * devices to end up in a bad state.
630 */
631 2 elan_stop_capture (self);
632 2 }
633
634 static void
635 2 elan_capture (FpiDeviceElan *self)
636 {
637 2 G_DEBUG_HERE ();
638
639 2 elan_dev_reset_state (self);
640 2 FpiSsm *ssm =
641 2 fpi_ssm_new (FP_DEVICE (self), capture_run_state, CAPTURE_NUM_STATES);
642
643 2 fpi_ssm_start (ssm, capture_complete);
644 2 }
645
646 /* this function needs to have elandev->background and elandev->last_read to be
647 * the calibration mean */
648 static int
649 3 elan_need_calibration (FpiDeviceElan *elandev)
650 {
651 3 G_DEBUG_HERE ();
652
653 3 unsigned short calib_mean =
654 3 elandev->last_read[0] * 0xff + elandev->last_read[1];
655 3 unsigned int bg_mean = 0, delta;
656 3 unsigned int frame_size = elandev->frame_width * elandev->frame_height;
657
658
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 3 times.
3 g_assert (frame_size != 0);
659
660
1/2
✓ Branch 6 → 7 taken 3 times.
✗ Branch 6 → 8 not taken.
3 if (elandev->dev_type == ELAN_0C42)
661 {
662 if (calib_mean > 5500 ||
663 calib_mean < 2500)
664 {
665 fp_dbg ("Forcing needed recalibration");
666 return 1;
667 }
668 }
669
670
2/2
✓ Branch 12 → 11 taken 21600 times.
✓ Branch 12 → 13 taken 3 times.
21603 for (int i = 0; i < frame_size; i++)
671 21600 bg_mean += elandev->background[i];
672 3 bg_mean /= frame_size;
673
674 3 delta =
675
1/2
✗ Branch 13 → 14 not taken.
✓ Branch 13 → 15 taken 3 times.
3 bg_mean > calib_mean ? bg_mean - calib_mean : calib_mean - bg_mean;
676
677 3 fp_dbg ("calibration mean: %d, bg mean: %d, delta: %d", calib_mean,
678 bg_mean, delta);
679
680 3 return delta > ELAN_CALIBRATION_MAX_DELTA ? 1 : 0;
681 }
682
683 enum calibrate_states {
684 CALIBRATE_GET_BACKGROUND,
685 CALIBRATE_SAVE_BACKGROUND,
686 CALIBRATE_GET_MEAN,
687 CALIBRATE_CHECK_NEEDED,
688 CALIBRATE_GET_STATUS,
689 CALIBRATE_CHECK_STATUS,
690 CALIBRATE_REPEAT_STATUS,
691 CALIBRATE_NUM_STATES,
692 };
693
694 static gboolean
695 3 elan_supports_calibration (FpiDeviceElan *elandev)
696 {
697 3 if (elandev->dev_type == ELAN_0C42)
698 return TRUE;
699
700 3 return elandev->fw_ver >= ELAN_MIN_CALIBRATION_FW;
701 }
702
703 static void
704 29 calibrate_run_state (FpiSsm *ssm, FpDevice *dev)
705 {
706 29 FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
707
708 29 G_DEBUG_HERE ();
709
710
7/8
✓ Branch 5 → 6 taken 3 times.
✓ Branch 5 → 8 taken 3 times.
✓ Branch 5 → 14 taken 3 times.
✓ Branch 5 → 16 taken 3 times.
✓ Branch 5 → 20 taken 6 times.
✓ Branch 5 → 25 taken 6 times.
✓ Branch 5 → 33 taken 5 times.
✗ Branch 5 → 35 not taken.
29 switch (fpi_ssm_get_cur_state (ssm))
711 {
712 3 case CALIBRATE_GET_BACKGROUND:
713 3 elan_run_cmd (ssm, dev, &get_image_cmd, ELAN_CMD_TIMEOUT);
714 3 break;
715
716 3 case CALIBRATE_SAVE_BACKGROUND:
717 3 elan_save_background (self);
718
2/4
✓ Branch 9 → 10 taken 3 times.
✗ Branch 9 → 13 not taken.
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 13 taken 3 times.
3 if (!elan_supports_calibration (self))
719 {
720 fp_dbg ("FW does not support calibration");
721 fpi_ssm_mark_completed (ssm);
722 }
723 else
724 {
725 3 fpi_ssm_next_state (ssm);
726 }
727 break;
728
729 3 case CALIBRATE_GET_MEAN:
730 3 elan_run_cmd (ssm, dev, &get_calib_mean_cmd, ELAN_CMD_TIMEOUT);
731 3 break;
732
733 3 case CALIBRATE_CHECK_NEEDED:
734
2/2
✓ Branch 17 → 18 taken 1 time.
✓ Branch 17 → 19 taken 2 times.
3 if (elan_need_calibration (self))
735 {
736 1 self->calib_status = 0;
737 1 fpi_ssm_next_state (ssm);
738 }
739 else
740 {
741 2 fpi_ssm_mark_completed (ssm);
742 }
743 break;
744
745 6 case CALIBRATE_GET_STATUS:
746 6 self->calib_atts_left -= 1;
747
1/2
✓ Branch 20 → 21 taken 6 times.
✗ Branch 20 → 22 not taken.
6 if (self->calib_atts_left)
748 {
749 6 elan_run_cmd (ssm, dev, &get_calib_status_cmd,
750 ELAN_CMD_TIMEOUT);
751 }
752 else
753 {
754 fp_dbg ("calibration failed");
755 fpi_ssm_mark_failed (ssm,
756 fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL,
757 "Calibration failed!"));
758 }
759 break;
760
761 6 case CALIBRATE_CHECK_STATUS:
762 /* 0x01 - retry, 0x03 - ok
763 * It appears that when reading the response soon after 0x4023 the device
764 * can return 0x03, and only after some time (up to 100 ms) the response
765 * changes to 0x01. It stays that way for some time and then changes back
766 * to 0x03. Because of this we don't just expect 0x03, we want to see 0x01
767 * first. This is to make sure that a full calibration loop has completed */
768 6 fp_dbg ("calibration status: 0x%02x", self->last_read[0]);
769
2/2
✓ Branch 26 → 27 taken 5 times.
✓ Branch 26 → 29 taken 1 time.
6 if (self->calib_status == 0x01 &&
770
2/2
✓ Branch 27 → 28 taken 1 time.
✓ Branch 27 → 29 taken 4 times.
5 self->last_read[0] == 0x03)
771 {
772 1 self->calib_status = 0x03;
773 1 fpi_ssm_jump_to_state (ssm, CALIBRATE_GET_BACKGROUND);
774 }
775 else
776 {
777
2/2
✓ Branch 29 → 30 taken 1 time.
✓ Branch 29 → 32 taken 4 times.
5 if (self->calib_status == 0x00 &&
778
1/2
✓ Branch 30 → 31 taken 1 time.
✗ Branch 30 → 32 not taken.
1 self->last_read[0] == 0x01)
779 1 self->calib_status = 0x01;
780 5 fpi_ssm_next_state_delayed (ssm, 50);
781 }
782 break;
783
784 5 case CALIBRATE_REPEAT_STATUS:
785 5 fpi_ssm_jump_to_state (ssm, CALIBRATE_GET_STATUS);
786 5 break;
787 }
788 29 }
789
790 static void
791 2 calibrate_complete (FpiSsm *ssm, FpDevice *dev, GError *error)
792 {
793 2 G_DEBUG_HERE ();
794
795
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 7 taken 2 times.
2 if (error)
796 {
797 fpi_image_device_session_error (FP_IMAGE_DEVICE (dev), error);
798 elan_stop_capture (FPI_DEVICE_ELAN (dev));
799 }
800 else
801 {
802 2 elan_capture (FPI_DEVICE_ELAN (dev));
803 }
804 2 }
805
806 static void
807 2 elan_calibrate (FpiDeviceElan *self)
808 {
809 2 G_DEBUG_HERE ();
810
811 2 elan_dev_reset_state (self);
812
813
1/2
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 2 times.
2 g_return_if_fail (!self->active);
814 2 self->active = TRUE;
815
1/2
✓ Branch 7 → 8 taken 2 times.
✗ Branch 7 → 9 not taken.
2 self->calib_atts_left = ELAN_CALIBRATION_ATTEMPTS (self->dev_type);
816
817 2 FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (self), calibrate_run_state,
818 CALIBRATE_NUM_STATES);
819
820 2 fpi_ssm_start (ssm, calibrate_complete);
821 }
822
823 enum activate_states {
824 ACTIVATE_GET_FW_VER,
825 ACTIVATE_SET_FW_VER,
826 ACTIVATE_GET_SENSOR_DIM,
827 ACTIVATE_SET_SENSOR_DIM,
828 ACTIVATE_CMD_1,
829 ACTIVATE_NUM_STATES,
830 };
831
832 static void
833 10 activate_run_state (FpiSsm *ssm, FpDevice *dev)
834 {
835 10 FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
836
837 10 G_DEBUG_HERE ();
838
839
5/6
✓ Branch 5 → 6 taken 2 times.
✓ Branch 5 → 8 taken 2 times.
✓ Branch 5 → 11 taken 2 times.
✓ Branch 5 → 13 taken 2 times.
✓ Branch 5 → 24 taken 2 times.
✗ Branch 5 → 26 not taken.
10 switch (fpi_ssm_get_cur_state (ssm))
840 {
841 2 case ACTIVATE_GET_FW_VER:
842 2 elan_run_cmd (ssm, dev, &get_fw_ver_cmd, ELAN_CMD_TIMEOUT);
843 2 break;
844
845 2 case ACTIVATE_SET_FW_VER:
846 2 self->fw_ver =
847 2 (self->last_read[0] << 8 | self->last_read[1]);
848 2 fp_dbg ("FW ver 0x%04hx", self->fw_ver);
849 2 fpi_ssm_next_state (ssm);
850 2 break;
851
852 2 case ACTIVATE_GET_SENSOR_DIM:
853 2 elan_run_cmd (ssm, dev, &get_sensor_dim_cmd, ELAN_CMD_TIMEOUT);
854 2 break;
855
856 2 case ACTIVATE_SET_SENSOR_DIM:
857 /* see elan_save_frame for details */
858
1/2
✗ Branch 13 → 14 not taken.
✓ Branch 13 → 15 taken 2 times.
2 if (self->dev_type & ELAN_NOT_ROTATED)
859 {
860 self->frame_width = self->last_read[0];
861 self->frame_height = self->raw_frame_height =
862 self->last_read[2];
863 }
864 else
865 {
866 2 self->frame_width = self->last_read[2];
867 2 self->frame_height = self->raw_frame_height =
868 2 self->last_read[0];
869 }
870 /* Work-around sensors returning the sizes as zero-based index
871 * rather than the number of pixels. */
872
1/2
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 19 taken 2 times.
2 if ((self->frame_width % 2 == 1) &&
873 (self->frame_height % 2 == 1))
874 {
875 self->frame_width++;
876 self->frame_height++;
877 self->raw_frame_height = self->frame_height;
878 }
879
1/2
✓ Branch 19 → 20 taken 2 times.
✗ Branch 19 → 21 not taken.
2 if (self->frame_height > ELAN_MAX_FRAME_HEIGHT)
880 2 self->frame_height = ELAN_MAX_FRAME_HEIGHT;
881 2 fp_dbg ("sensor dimensions, WxH: %dx%d", self->frame_width,
882 self->raw_frame_height);
883 2 fpi_ssm_next_state (ssm);
884 2 break;
885
886 2 case ACTIVATE_CMD_1:
887 /* TODO: find out what this does, if we need it */
888 2 elan_run_cmd (ssm, dev, &activate_cmd_1, ELAN_CMD_TIMEOUT);
889 2 break;
890 }
891 10 }
892
893 static void
894 2 activate_complete (FpiSsm *ssm, FpDevice *dev, GError *error)
895 {
896 2 FpImageDevice *idev = FP_IMAGE_DEVICE (dev);
897
898 2 G_DEBUG_HERE ();
899
900 2 fpi_image_device_activate_complete (idev, error);
901
902 2 }
903
904 static void
905 2 elan_activate (FpImageDevice *dev)
906 {
907 2 FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
908
909 2 G_DEBUG_HERE ();
910 2 elan_dev_reset_state (self);
911
912 2 FpiSsm *ssm =
913 2 fpi_ssm_new (FP_DEVICE (dev), activate_run_state,
914 ACTIVATE_NUM_STATES);
915
916 2 fpi_ssm_start (ssm, activate_complete);
917 2 }
918
919 static void
920 2 dev_init (FpImageDevice *dev)
921 {
922 2 GError *error = NULL;
923 2 FpiDeviceElan *self;
924
925 2 G_DEBUG_HERE ();
926
927
1/2
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 9 taken 2 times.
2 if (!g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error))
928 {
929 fpi_image_device_open_complete (dev, error);
930 return;
931 }
932
933 2 self = FPI_DEVICE_ELAN (dev);
934
935 /* common params */
936 2 self->dev_type = fpi_device_get_driver_data (FP_DEVICE (dev));
937 2 self->background = NULL;
938 2 self->process_frame = elan_process_frame_thirds;
939
940
1/2
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 2 times.
2 switch (self->dev_type)
941 {
942 case ELAN_0907:
943 self->process_frame = elan_process_frame_linear;
944 break;
945 }
946
947 2 fpi_image_device_open_complete (dev, NULL);
948 }
949
950 static void
951 2 dev_deinit (FpImageDevice *dev)
952 {
953 2 GError *error = NULL;
954 2 FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
955
956 2 G_DEBUG_HERE ();
957
958 2 elan_dev_reset_state (self);
959 2 g_free (self->background);
960 2 g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)),
961 0, 0, &error);
962 2 fpi_image_device_close_complete (dev, error);
963 2 }
964
965 static void
966 2 dev_activate (FpImageDevice *dev)
967 {
968 2 G_DEBUG_HERE ();
969 2 elan_activate (dev);
970 2 }
971
972 static void
973 16 dev_change_state (FpImageDevice *dev, FpiImageDeviceState state)
974 {
975 16 FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
976
977 16 G_DEBUG_HERE ();
978
979 /* Note: We always calibrate even if that may not be needed always.
980 * Doing this for each capture appears to make it at least less likely for
981 * devices to end up in a bad state.
982 */
983
2/2
✓ Branch 4 → 5 taken 2 times.
✓ Branch 4 → 6 taken 14 times.
16 if (state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON)
984 2 elan_calibrate (self);
985 16 }
986
987 static void
988 2 dev_deactivate (FpImageDevice *dev)
989 {
990 2 FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
991
992 2 G_DEBUG_HERE ();
993
994
1/2
✓ Branch 4 → 5 taken 2 times.
✗ Branch 4 → 6 not taken.
2 if (!self->active)
995 /* The device is inactive already, complete the operation immediately. */
996 2 fpi_image_device_deactivate_complete (dev, NULL);
997 else
998 /* The device is not yet inactive, flag that we are deactivating (and
999 * need to signal back deactivation).
1000 * Note that any running capture will be cancelled already if needed. */
1001 self->deactivating = TRUE;
1002 2 }
1003
1004 static void
1005 2 fpi_device_elan_init (FpiDeviceElan *self)
1006 {
1007 2 }
1008 static void
1009 127 fpi_device_elan_class_init (FpiDeviceElanClass *klass)
1010 {
1011 127 FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
1012 127 FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
1013
1014 127 dev_class->id = "elan";
1015 127 dev_class->full_name = "ElanTech Fingerprint Sensor";
1016 127 dev_class->type = FP_DEVICE_TYPE_USB;
1017 127 dev_class->id_table = elan_id_table;
1018 127 dev_class->scan_type = FP_SCAN_TYPE_SWIPE;
1019
1020 127 img_class->img_open = dev_init;
1021 127 img_class->img_close = dev_deinit;
1022 127 img_class->activate = dev_activate;
1023 127 img_class->deactivate = dev_deactivate;
1024 127 img_class->change_state = dev_change_state;
1025
1026 127 img_class->bz3_threshold = 24;
1027 }
1028