GCC Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 86.7% 383 / 0 / 442
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 125 times.
fpi_device_elan_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 (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 ((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 g_assert (max != min);
255
256 unsigned short px;
257
258 for (int i = 0; i < frame_size; i++)
259 {
260 px = raw_frame[i];
261 px = (px - min) * 0xff / (max - min);
262 frame->data[i] = (unsigned char) px;
263 }
264
265 *frames = g_slist_prepend (*frames, frame);
266 }
267
268 static void
269 24 elan_process_frame_thirds (unsigned short *raw_frame,
270 GSList ** frames)
271 {
272 24 G_DEBUG_HERE ();
273
274 24 unsigned int frame_size =
275 24 assembling_ctx.frame_width * assembling_ctx.frame_height;
276 24 struct fpi_frame *frame =
277 24 g_malloc (frame_size + sizeof (struct fpi_frame));
278
279 24 unsigned short lvl0, lvl1, lvl2, lvl3;
280 24 unsigned short *sorted = g_malloc (frame_size * sizeof (short));
281
282 24 memcpy (sorted, raw_frame, frame_size * sizeof (short));
283 24 qsort (sorted, frame_size, sizeof (short), cmp_short);
284 24 lvl0 = sorted[0];
285 24 lvl1 = sorted[frame_size * 3 / 10];
286 24 lvl2 = sorted[frame_size * 65 / 100];
287 24 lvl3 = sorted[frame_size - 1];
288 24 g_free (sorted);
289
290 24 unsigned short px;
291
292
2/2
✓ Branch 15 → 9 taken 172800 times.
✓ Branch 15 → 16 taken 24 times.
172848 for (int i = 0; i < frame_size; i++)
293 {
294 172800 px = raw_frame[i];
295
2/2
✓ Branch 9 → 10 taken 51794 times.
✓ Branch 9 → 11 taken 121006 times.
172800 if (lvl0 <= px && px < lvl1)
296 51794 px = (px - lvl0) * 99 / (lvl1 - lvl0);
297
2/2
✓ Branch 11 → 12 taken 60488 times.
✓ Branch 11 → 13 taken 60518 times.
121006 else if (lvl1 <= px && px < lvl2)
298 60488 px = 99 + ((px - lvl1) * 56 / (lvl2 - lvl1));
299 else // (lvl2 <= px && px <= lvl3)
300 60518 px = 155 + ((px - lvl2) * 100 / (lvl3 - lvl2));
301 172800 frame->data[i] = (unsigned char) px;
302 }
303
304 24 *frames = g_slist_prepend (*frames, frame);
305 24 }
306
307 static void
308 2 elan_submit_image (FpImageDevice *dev)
309 {
310 2 FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
311 2 GSList *raw_frames;
312 2 GSList *frames = NULL;
313 2 FpImage *img;
314
315 2 G_DEBUG_HERE ();
316
317 2 raw_frames = g_slist_nth (self->frames, ELAN_SKIP_LAST_FRAMES);
318
319 2 assembling_ctx.frame_width = self->frame_width;
320 2 assembling_ctx.frame_height = self->frame_height;
321 2 assembling_ctx.image_width = self->frame_width * 3 / 2;
322 2 g_slist_foreach (raw_frames, (GFunc) self->process_frame, &frames);
323 2 fpi_do_movement_estimation (&assembling_ctx, frames);
324 2 img = fpi_assemble_frames (&assembling_ctx, frames);
325 2 img->flags |= FPI_IMAGE_PARTIAL;
326
327 2 g_slist_free_full (frames, g_free);
328
329 2 fpi_image_device_image_captured (dev, img);
330 2 }
331
332 static void
333 80 elan_cmd_done (FpiSsm *ssm)
334 {
335 80 G_DEBUG_HERE ();
336 80 fpi_ssm_next_state (ssm);
337 80 }
338
339 static void
340 152 elan_cmd_cb (FpiUsbTransfer *transfer, FpDevice *dev,
341 gpointer user_data, GError *error)
342 {
343 152 FpiSsm *ssm = transfer->ssm;
344 152 FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
345
346 152 G_DEBUG_HERE ();
347
348
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 7 taken 152 times.
152 if (error)
349 {
350 /* XXX: In the cancellation case we used to not
351 * mark the SSM as failed?! */
352 fpi_ssm_mark_failed (transfer->ssm, error);
353 return;
354 }
355
356 /* XXX: We used to reset the device in error cases! */
357
2/2
✓ Branch 7 → 8 taken 74 times.
✓ Branch 7 → 10 taken 78 times.
152 if (transfer->endpoint & FPI_USB_ENDPOINT_IN)
358 {
359 /* just finished receiving */
360 74 self->last_read = g_memdup2 (transfer->buffer, transfer->actual_length);
361 74 elan_cmd_done (ssm);
362 }
363 else
364 {
365 /* just finished sending */
366 78 G_DEBUG_HERE ();
367 78 elan_cmd_read (ssm, dev);
368 }
369 }
370
371 static void
372 78 elan_cmd_read (FpiSsm *ssm, FpDevice *dev)
373 {
374 78 FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
375 78 FpiUsbTransfer *transfer;
376 78 GCancellable *cancellable = NULL;
377 78 int response_len = self->cmd->response_len;
378
379 78 G_DEBUG_HERE ();
380
381
2/2
✓ Branch 4 → 5 taken 4 times.
✓ Branch 4 → 8 taken 74 times.
78 if (self->cmd->response_len == ELAN_CMD_SKIP_READ)
382 {
383 4 fp_dbg ("skipping read, not expecting anything");
384 4 elan_cmd_done (ssm);
385 4 return;
386 }
387
388
1/2
✓ Branch 8 → 9 taken 74 times.
✗ Branch 8 → 10 not taken.
74 if (self->dev_type == ELAN_0C42)
389 {
390 /* ELAN_0C42 sends an extra byte in one byte responses */
391 if (self->cmd->response_len == 1)
392 74 response_len = 2;
393 }
394
395
2/2
✓ Branch 11 → 12 taken 31 times.
✓ Branch 11 → 13 taken 43 times.
74 if (self->cmd->cmd == get_image_cmd.cmd)
396 /* raw data has 2-byte "pixels" and the frame is vertical */
397 31 response_len =
398 31 self->raw_frame_height * self->frame_width * 2;
399
400
2/2
✓ Branch 13 → 14 taken 68 times.
✓ Branch 13 → 15 taken 6 times.
74 g_clear_pointer (&self->last_read, g_free);
401
402 74 transfer = fpi_usb_transfer_new (dev);
403 74 transfer->ssm = ssm;
404 74 transfer->short_is_error = TRUE;
405
406 74 fpi_usb_transfer_fill_bulk (transfer,
407 74 self->cmd->response_in,
408 response_len);
409
410
1/2
✓ Branch 17 → 18 taken 74 times.
✗ Branch 17 → 19 not taken.
74 if (!self->cmd->never_cancel)
411 74 cancellable = fpi_device_get_cancellable (dev);
412
413 74 fpi_usb_transfer_submit (transfer, self->cmd_timeout, cancellable, elan_cmd_cb, NULL);
414 }
415
416 static void
417 80 elan_run_cmd (FpiSsm *ssm,
418 FpDevice *dev,
419 const struct elan_cmd *cmd,
420 int cmd_timeout)
421 {
422 80 FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
423 80 FpiUsbTransfer *transfer;
424 80 GCancellable *cancellable = NULL;
425
426 80 self->cmd = cmd;
427
2/2
✓ Branch 2 → 3 taken 50 times.
✓ Branch 2 → 4 taken 30 times.
80 if (cmd_timeout != -1)
428 50 self->cmd_timeout = cmd_timeout;
429
430
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))
431 {
432 2 fp_dbg ("skipping command 0x%x 0x%x for this device (for devices 0x%x but device is 0x%x)",
433 cmd->cmd[0], cmd->cmd[1], cmd->devices, self->dev_type);
434 2 elan_cmd_done (ssm);
435 2 return;
436 }
437
438 78 transfer = fpi_usb_transfer_new (dev);
439 78 transfer->ssm = ssm;
440 78 transfer->short_is_error = TRUE;
441
442 78 fpi_usb_transfer_fill_bulk_full (transfer,
443 ELAN_EP_CMD_OUT,
444 78 (guint8 *) cmd->cmd,
445 ELAN_CMD_LEN,
446 NULL);
447
448
2/2
✓ Branch 11 → 12 taken 76 times.
✓ Branch 11 → 13 taken 2 times.
78 if (!self->cmd->never_cancel)
449 76 cancellable = fpi_device_get_cancellable (dev);
450
451 78 fpi_usb_transfer_submit (transfer,
452 78 self->cmd_timeout,
453 cancellable,
454 elan_cmd_cb,
455 NULL);
456 }
457
458 enum stop_capture_states {
459 STOP_CAPTURE,
460 STOP_CAPTURE_NUM_STATES,
461 };
462
463 static void
464 2 stop_capture_run_state (FpiSsm *ssm, FpDevice *dev)
465 {
466 2 G_DEBUG_HERE ();
467
468
1/2
✓ Branch 5 → 6 taken 2 times.
✗ Branch 5 → 8 not taken.
2 switch (fpi_ssm_get_cur_state (ssm))
469 {
470 2 case STOP_CAPTURE:
471 2 elan_run_cmd (ssm, dev, &stop_cmd,
472 ELAN_CMD_TIMEOUT);
473 2 break;
474 }
475 2 }
476
477 static void
478 2 stop_capture_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
479 {
480 2 FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
481 2 FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
482
483 2 G_DEBUG_HERE ();
484
485
486 /* The device is inactive at this point. */
487 2 self->active = FALSE;
488
489
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 7 taken 2 times.
2 if (self->deactivating)
490 {
491 /* Simply complete the pending deactivation. */
492 self->deactivating = FALSE;
493 fpi_image_device_deactivate_complete (dev, error);
494 return;
495 }
496
497
1/2
✓ Branch 7 → 8 taken 2 times.
✗ Branch 7 → 9 not taken.
2 if (!error)
498 2 fpi_image_device_report_finger_status (dev, FALSE);
499 else
500 /* NOTE: We cannot get a cancellation error here. */
501 fpi_image_device_session_error (dev, error);
502 }
503
504 static void
505 2 elan_stop_capture (FpiDeviceElan *self)
506 {
507 2 G_DEBUG_HERE ();
508
509 2 elan_dev_reset_state (self);
510
511 2 FpiSsm *ssm =
512 2 fpi_ssm_new (FP_DEVICE (self), stop_capture_run_state, STOP_CAPTURE_NUM_STATES);
513
514 2 fpi_ssm_start (ssm, stop_capture_complete);
515 2 }
516
517 enum capture_states {
518 CAPTURE_LED_ON,
519 CAPTURE_WAIT_FINGER,
520 CAPTURE_READ_DATA,
521 CAPTURE_CHECK_ENOUGH_FRAMES,
522 CAPTURE_NUM_STATES,
523 };
524
525 static void
526 90 capture_run_state (FpiSsm *ssm, FpDevice *dev)
527 {
528 90 FpImageDevice *idev = FP_IMAGE_DEVICE (dev);
529 90 FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
530 90 int r;
531
532
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))
533 {
534 2 case CAPTURE_LED_ON:
535 2 elan_run_cmd (ssm, dev, &led_on_cmd, ELAN_CMD_TIMEOUT);
536 2 break;
537
538 30 case CAPTURE_WAIT_FINGER:
539 30 elan_run_cmd (ssm, dev, &pre_scan_cmd, -1);
540 30 break;
541
542 30 case CAPTURE_READ_DATA:
543 /* 0x55 - finger present
544 * 0xff - device not calibrated (probably) */
545
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)
546 {
547 28 fpi_image_device_report_finger_status (idev, TRUE);
548 28 elan_run_cmd (ssm, dev, &get_image_cmd, ELAN_CMD_TIMEOUT);
549 }
550
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 &&
551 (self->last_read[0] == 0x00 || self->last_read[0] == 0xaf))
552 {
553 /* 0x00 - not ready
554 * 0xaf - finger removed or sensor busy (seen on 0x0c58) */
555 fpi_ssm_jump_to_state_delayed (ssm, CAPTURE_WAIT_FINGER, 10);
556 }
557 else
558 {
559 /* XXX: The timeout is emulated incorrectly, resulting in a zero byte read. */
560
1/2
✗ Branch 17 → 18 not taken.
✓ Branch 17 → 20 taken 2 times.
2 if (fpi_device_emulation_mode_enabled (FP_DEVICE (self)))
561 2 fpi_ssm_mark_completed (ssm);
562 else
563 fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
564 }
565 break;
566
567 28 case CAPTURE_CHECK_ENOUGH_FRAMES:
568 28 r = elan_save_img_frame (self);
569
1/2
✗ Branch 22 → 23 not taken.
✓ Branch 22 → 25 taken 28 times.
28 if (r < 0)
570 {
571 fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
572 }
573
1/2
✓ Branch 25 → 26 taken 28 times.
✗ Branch 25 → 27 not taken.
28 else if (self->num_frames < ELAN_MAX_FRAMES)
574 {
575 /* quickly stop if finger is removed */
576 28 self->cmd_timeout = ELAN_FINGER_TIMEOUT;
577 28 fpi_ssm_jump_to_state (ssm, CAPTURE_WAIT_FINGER);
578 }
579 else
580 {
581 fpi_ssm_next_state (ssm);
582 }
583 break;
584 }
585 90 }
586
587 static void
588 2 capture_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
589 {
590 2 FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
591 2 FpiDeviceElan *self = FPI_DEVICE_ELAN (_dev);
592
593 2 G_DEBUG_HERE ();
594
595 /* either max frames captured or timed out waiting for the next frame */
596
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 ||
597 (g_error_matches (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_TIMED_OUT) &&
598 fpi_ssm_get_cur_state (ssm) == CAPTURE_WAIT_FINGER))
599 {
600
1/2
✓ Branch 10 → 11 taken 2 times.
✗ Branch 10 → 12 not taken.
2 if (self->num_frames >= ELAN_MIN_FRAMES)
601 {
602 2 elan_submit_image (dev);
603 }
604 else
605 {
606 fp_dbg ("swipe too short: want >= %d frames, got %d",
607 ELAN_MIN_FRAMES, self->num_frames);
608 fpi_image_device_retry_scan (dev, FP_DEVICE_RETRY_TOO_SHORT);
609 }
610 2 g_clear_error (&error);
611 }
612 else
613 {
614 fpi_image_device_session_error (dev, error);
615 }
616
617 /* Note: We always stop capturing even if that may not be needed always.
618 * Doing this between captures appears to make it at least less likely for
619 * devices to end up in a bad state.
620 */
621 2 elan_stop_capture (self);
622 2 }
623
624 static void
625 2 elan_capture (FpiDeviceElan *self)
626 {
627 2 G_DEBUG_HERE ();
628
629 2 elan_dev_reset_state (self);
630 2 FpiSsm *ssm =
631 2 fpi_ssm_new (FP_DEVICE (self), capture_run_state, CAPTURE_NUM_STATES);
632
633 2 fpi_ssm_start (ssm, capture_complete);
634 2 }
635
636 /* this function needs to have elandev->background and elandev->last_read to be
637 * the calibration mean */
638 static int
639 3 elan_need_calibration (FpiDeviceElan *elandev)
640 {
641 3 G_DEBUG_HERE ();
642
643 3 unsigned short calib_mean =
644 3 elandev->last_read[0] * 0xff + elandev->last_read[1];
645 3 unsigned int bg_mean = 0, delta;
646 3 unsigned int frame_size = elandev->frame_width * elandev->frame_height;
647
648
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 3 times.
3 g_assert (frame_size != 0);
649
650
1/2
✓ Branch 6 → 7 taken 3 times.
✗ Branch 6 → 8 not taken.
3 if (elandev->dev_type == ELAN_0C42)
651 {
652 if (calib_mean > 5500 ||
653 calib_mean < 2500)
654 {
655 fp_dbg ("Forcing needed recalibration");
656 return 1;
657 }
658 }
659
660
2/2
✓ Branch 12 → 11 taken 21600 times.
✓ Branch 12 → 13 taken 3 times.
21603 for (int i = 0; i < frame_size; i++)
661 21600 bg_mean += elandev->background[i];
662 3 bg_mean /= frame_size;
663
664 3 delta =
665
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;
666
667 3 fp_dbg ("calibration mean: %d, bg mean: %d, delta: %d", calib_mean,
668 bg_mean, delta);
669
670 3 return delta > ELAN_CALIBRATION_MAX_DELTA ? 1 : 0;
671 }
672
673 enum calibrate_states {
674 CALIBRATE_GET_BACKGROUND,
675 CALIBRATE_SAVE_BACKGROUND,
676 CALIBRATE_GET_MEAN,
677 CALIBRATE_CHECK_NEEDED,
678 CALIBRATE_GET_STATUS,
679 CALIBRATE_CHECK_STATUS,
680 CALIBRATE_REPEAT_STATUS,
681 CALIBRATE_NUM_STATES,
682 };
683
684 static gboolean
685 3 elan_supports_calibration (FpiDeviceElan *elandev)
686 {
687 3 if (elandev->dev_type == ELAN_0C42)
688 return TRUE;
689
690 3 return elandev->fw_ver >= ELAN_MIN_CALIBRATION_FW;
691 }
692
693 static void
694 29 calibrate_run_state (FpiSsm *ssm, FpDevice *dev)
695 {
696 29 FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
697
698 29 G_DEBUG_HERE ();
699
700
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))
701 {
702 3 case CALIBRATE_GET_BACKGROUND:
703 3 elan_run_cmd (ssm, dev, &get_image_cmd, ELAN_CMD_TIMEOUT);
704 3 break;
705
706 3 case CALIBRATE_SAVE_BACKGROUND:
707 3 elan_save_background (self);
708
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))
709 {
710 fp_dbg ("FW does not support calibration");
711 fpi_ssm_mark_completed (ssm);
712 }
713 else
714 {
715 3 fpi_ssm_next_state (ssm);
716 }
717 break;
718
719 3 case CALIBRATE_GET_MEAN:
720 3 elan_run_cmd (ssm, dev, &get_calib_mean_cmd, ELAN_CMD_TIMEOUT);
721 3 break;
722
723 3 case CALIBRATE_CHECK_NEEDED:
724
2/2
✓ Branch 17 → 18 taken 1 time.
✓ Branch 17 → 19 taken 2 times.
3 if (elan_need_calibration (self))
725 {
726 1 self->calib_status = 0;
727 1 fpi_ssm_next_state (ssm);
728 }
729 else
730 {
731 2 fpi_ssm_mark_completed (ssm);
732 }
733 break;
734
735 6 case CALIBRATE_GET_STATUS:
736 6 self->calib_atts_left -= 1;
737
1/2
✓ Branch 20 → 21 taken 6 times.
✗ Branch 20 → 22 not taken.
6 if (self->calib_atts_left)
738 {
739 6 elan_run_cmd (ssm, dev, &get_calib_status_cmd,
740 ELAN_CMD_TIMEOUT);
741 }
742 else
743 {
744 fp_dbg ("calibration failed");
745 fpi_ssm_mark_failed (ssm,
746 fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL,
747 "Calibration failed!"));
748 }
749 break;
750
751 6 case CALIBRATE_CHECK_STATUS:
752 /* 0x01 - retry, 0x03 - ok
753 * It appears that when reading the response soon after 0x4023 the device
754 * can return 0x03, and only after some time (up to 100 ms) the response
755 * changes to 0x01. It stays that way for some time and then changes back
756 * to 0x03. Because of this we don't just expect 0x03, we want to see 0x01
757 * first. This is to make sure that a full calibration loop has completed */
758 6 fp_dbg ("calibration status: 0x%02x", self->last_read[0]);
759
2/2
✓ Branch 26 → 27 taken 5 times.
✓ Branch 26 → 29 taken 1 time.
6 if (self->calib_status == 0x01 &&
760
2/2
✓ Branch 27 → 28 taken 1 time.
✓ Branch 27 → 29 taken 4 times.
5 self->last_read[0] == 0x03)
761 {
762 1 self->calib_status = 0x03;
763 1 fpi_ssm_jump_to_state (ssm, CALIBRATE_GET_BACKGROUND);
764 }
765 else
766 {
767
2/2
✓ Branch 29 → 30 taken 1 time.
✓ Branch 29 → 32 taken 4 times.
5 if (self->calib_status == 0x00 &&
768
1/2
✓ Branch 30 → 31 taken 1 time.
✗ Branch 30 → 32 not taken.
1 self->last_read[0] == 0x01)
769 1 self->calib_status = 0x01;
770 5 fpi_ssm_next_state_delayed (ssm, 50);
771 }
772 break;
773
774 5 case CALIBRATE_REPEAT_STATUS:
775 5 fpi_ssm_jump_to_state (ssm, CALIBRATE_GET_STATUS);
776 5 break;
777 }
778 29 }
779
780 static void
781 2 calibrate_complete (FpiSsm *ssm, FpDevice *dev, GError *error)
782 {
783 2 G_DEBUG_HERE ();
784
785
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 7 taken 2 times.
2 if (error)
786 {
787 fpi_image_device_session_error (FP_IMAGE_DEVICE (dev), error);
788 elan_stop_capture (FPI_DEVICE_ELAN (dev));
789 }
790 else
791 {
792 2 elan_capture (FPI_DEVICE_ELAN (dev));
793 }
794 2 }
795
796 static void
797 2 elan_calibrate (FpiDeviceElan *self)
798 {
799 2 G_DEBUG_HERE ();
800
801 2 elan_dev_reset_state (self);
802
803
1/2
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 2 times.
2 g_return_if_fail (!self->active);
804 2 self->active = TRUE;
805
1/2
✓ Branch 7 → 8 taken 2 times.
✗ Branch 7 → 9 not taken.
2 self->calib_atts_left = ELAN_CALIBRATION_ATTEMPTS (self->dev_type);
806
807 2 FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (self), calibrate_run_state,
808 CALIBRATE_NUM_STATES);
809
810 2 fpi_ssm_start (ssm, calibrate_complete);
811 }
812
813 enum activate_states {
814 ACTIVATE_GET_FW_VER,
815 ACTIVATE_SET_FW_VER,
816 ACTIVATE_GET_SENSOR_DIM,
817 ACTIVATE_SET_SENSOR_DIM,
818 ACTIVATE_CMD_1,
819 ACTIVATE_NUM_STATES,
820 };
821
822 static void
823 10 activate_run_state (FpiSsm *ssm, FpDevice *dev)
824 {
825 10 FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
826
827 10 G_DEBUG_HERE ();
828
829
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))
830 {
831 2 case ACTIVATE_GET_FW_VER:
832 2 elan_run_cmd (ssm, dev, &get_fw_ver_cmd, ELAN_CMD_TIMEOUT);
833 2 break;
834
835 2 case ACTIVATE_SET_FW_VER:
836 2 self->fw_ver =
837 2 (self->last_read[0] << 8 | self->last_read[1]);
838 2 fp_dbg ("FW ver 0x%04hx", self->fw_ver);
839 2 fpi_ssm_next_state (ssm);
840 2 break;
841
842 2 case ACTIVATE_GET_SENSOR_DIM:
843 2 elan_run_cmd (ssm, dev, &get_sensor_dim_cmd, ELAN_CMD_TIMEOUT);
844 2 break;
845
846 2 case ACTIVATE_SET_SENSOR_DIM:
847 /* see elan_save_frame for details */
848
1/2
✗ Branch 13 → 14 not taken.
✓ Branch 13 → 15 taken 2 times.
2 if (self->dev_type & ELAN_NOT_ROTATED)
849 {
850 self->frame_width = self->last_read[0];
851 self->frame_height = self->raw_frame_height =
852 self->last_read[2];
853 }
854 else
855 {
856 2 self->frame_width = self->last_read[2];
857 2 self->frame_height = self->raw_frame_height =
858 2 self->last_read[0];
859 }
860 /* Work-around sensors returning the sizes as zero-based index
861 * rather than the number of pixels. */
862
1/2
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 19 taken 2 times.
2 if ((self->frame_width % 2 == 1) &&
863 (self->frame_height % 2 == 1))
864 {
865 self->frame_width++;
866 self->frame_height++;
867 self->raw_frame_height = self->frame_height;
868 }
869
1/2
✓ Branch 19 → 20 taken 2 times.
✗ Branch 19 → 21 not taken.
2 if (self->frame_height > ELAN_MAX_FRAME_HEIGHT)
870 2 self->frame_height = ELAN_MAX_FRAME_HEIGHT;
871 2 fp_dbg ("sensor dimensions, WxH: %dx%d", self->frame_width,
872 self->raw_frame_height);
873 2 fpi_ssm_next_state (ssm);
874 2 break;
875
876 2 case ACTIVATE_CMD_1:
877 /* TODO: find out what this does, if we need it */
878 2 elan_run_cmd (ssm, dev, &activate_cmd_1, ELAN_CMD_TIMEOUT);
879 2 break;
880 }
881 10 }
882
883 static void
884 2 activate_complete (FpiSsm *ssm, FpDevice *dev, GError *error)
885 {
886 2 FpImageDevice *idev = FP_IMAGE_DEVICE (dev);
887
888 2 G_DEBUG_HERE ();
889
890 2 fpi_image_device_activate_complete (idev, error);
891
892 2 }
893
894 static void
895 2 elan_activate (FpImageDevice *dev)
896 {
897 2 FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
898
899 2 G_DEBUG_HERE ();
900 2 elan_dev_reset_state (self);
901
902 2 FpiSsm *ssm =
903 2 fpi_ssm_new (FP_DEVICE (dev), activate_run_state,
904 ACTIVATE_NUM_STATES);
905
906 2 fpi_ssm_start (ssm, activate_complete);
907 2 }
908
909 static void
910 2 dev_init (FpImageDevice *dev)
911 {
912 2 GError *error = NULL;
913 2 FpiDeviceElan *self;
914
915 2 G_DEBUG_HERE ();
916
917
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))
918 {
919 fpi_image_device_open_complete (dev, error);
920 return;
921 }
922
923 2 self = FPI_DEVICE_ELAN (dev);
924
925 /* common params */
926 2 self->dev_type = fpi_device_get_driver_data (FP_DEVICE (dev));
927 2 self->background = NULL;
928 2 self->process_frame = elan_process_frame_thirds;
929
930
1/2
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 2 times.
2 switch (self->dev_type)
931 {
932 case ELAN_0907:
933 self->process_frame = elan_process_frame_linear;
934 break;
935 }
936
937 2 fpi_image_device_open_complete (dev, NULL);
938 }
939
940 static void
941 2 dev_deinit (FpImageDevice *dev)
942 {
943 2 GError *error = NULL;
944 2 FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
945
946 2 G_DEBUG_HERE ();
947
948 2 elan_dev_reset_state (self);
949 2 g_free (self->background);
950 2 g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)),
951 0, 0, &error);
952 2 fpi_image_device_close_complete (dev, error);
953 2 }
954
955 static void
956 2 dev_activate (FpImageDevice *dev)
957 {
958 2 G_DEBUG_HERE ();
959 2 elan_activate (dev);
960 2 }
961
962 static void
963 16 dev_change_state (FpImageDevice *dev, FpiImageDeviceState state)
964 {
965 16 FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
966
967 16 G_DEBUG_HERE ();
968
969 /* Note: We always calibrate even if that may not be needed always.
970 * Doing this for each capture appears to make it at least less likely for
971 * devices to end up in a bad state.
972 */
973
2/2
✓ Branch 4 → 5 taken 2 times.
✓ Branch 4 → 6 taken 14 times.
16 if (state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON)
974 2 elan_calibrate (self);
975 16 }
976
977 static void
978 2 dev_deactivate (FpImageDevice *dev)
979 {
980 2 FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
981
982 2 G_DEBUG_HERE ();
983
984
1/2
✓ Branch 4 → 5 taken 2 times.
✗ Branch 4 → 6 not taken.
2 if (!self->active)
985 /* The device is inactive already, complete the operation immediately. */
986 2 fpi_image_device_deactivate_complete (dev, NULL);
987 else
988 /* The device is not yet inactive, flag that we are deactivating (and
989 * need to signal back deactivation).
990 * Note that any running capture will be cancelled already if needed. */
991 self->deactivating = TRUE;
992 2 }
993
994 static void
995 2 fpi_device_elan_init (FpiDeviceElan *self)
996 {
997 2 }
998 static void
999 125 fpi_device_elan_class_init (FpiDeviceElanClass *klass)
1000 {
1001 125 FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
1002 125 FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
1003
1004 125 dev_class->id = "elan";
1005 125 dev_class->full_name = "ElanTech Fingerprint Sensor";
1006 125 dev_class->type = FP_DEVICE_TYPE_USB;
1007 125 dev_class->id_table = elan_id_table;
1008 125 dev_class->scan_type = FP_SCAN_TYPE_SWIPE;
1009
1010 125 img_class->img_open = dev_init;
1011 125 img_class->img_close = dev_deinit;
1012 125 img_class->activate = dev_activate;
1013 125 img_class->deactivate = dev_deactivate;
1014 125 img_class->change_state = dev_change_state;
1015
1016 125 img_class->bz3_threshold = 24;
1017 }
1018