GCC Code Coverage Report


Directory: ./
File: libfprint/drivers/elan.c
Date: 2024-09-16 14:36:32
Exec Total Coverage
Lines: 381 437 87.2%
Functions: 34 35 97.1%
Branches: 92 140 65.7%

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/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 (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 0 taken 1550 times.
✓ Branch 1 taken 31 times.
1581 for (int y = 0; y < frame_height; y++)
141
2/2
✓ Branch 0 taken 223200 times.
✓ Branch 1 taken 1550 times.
224750 for (int x = 0; x < frame_width; x++)
142 {
143
1/2
✗ Branch 0 not taken.
✓ Branch 1 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 1 taken 201600 times.
✓ Branch 2 taken 28 times.
201628 for (int i = 0; i < frame_size; i++)
212 {
213
2/2
✓ Branch 0 taken 3037 times.
✓ Branch 1 taken 198563 times.
201600 if (elandev->background[i] > frame[i])
214 3037 frame[i] = 0;
215 else
216 198563 frame[i] -= elandev->background[i];
217 201600 sum += frame[i];
218 }
219
220
1/2
✗ Branch 0 not taken.
✓ Branch 1 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 1 taken 172800 times.
✓ Branch 2 taken 24 times.
172824 for (int i = 0; i < frame_size; i++)
293 {
294 172800 px = raw_frame[i];
295
2/2
✓ Branch 0 taken 51794 times.
✓ Branch 1 taken 121006 times.
172800 if (lvl0 <= px && px < lvl1)
296 51794 px = (px - lvl0) * 99 / (lvl1 - lvl0);
297
2/2
✓ Branch 0 taken 60488 times.
✓ Branch 1 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 0 not taken.
✓ Branch 1 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 0 taken 74 times.
✓ Branch 1 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 0 taken 4 times.
✓ Branch 1 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 0 taken 74 times.
✗ Branch 1 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 0 taken 31 times.
✓ Branch 1 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 0 taken 68 times.
✓ Branch 1 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 0 taken 74 times.
✗ Branch 1 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 0 taken 50 times.
✓ Branch 1 taken 30 times.
80 if (cmd_timeout != -1)
428 50 self->cmd_timeout = cmd_timeout;
429
430
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 78 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 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 0 taken 76 times.
✓ Branch 1 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 1 taken 2 times.
✗ Branch 2 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 0 not taken.
✓ Branch 1 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 0 taken 2 times.
✗ Branch 1 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 1 taken 2 times.
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 30 times.
✓ Branch 4 taken 28 times.
✗ Branch 5 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 0 taken 28 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 28 times.
✗ Branch 3 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 else
551 {
552 /* XXX: The timeout is emulated incorrectly, resulting in a zero byte read. */
553
1/2
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0)
554 2 fpi_ssm_mark_completed (ssm);
555 else
556 fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
557 }
558 break;
559
560 28 case CAPTURE_CHECK_ENOUGH_FRAMES:
561 28 r = elan_save_img_frame (self);
562
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
28 if (r < 0)
563 {
564 fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
565 }
566
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 else if (self->num_frames < ELAN_MAX_FRAMES)
567 {
568 /* quickly stop if finger is removed */
569 28 self->cmd_timeout = ELAN_FINGER_TIMEOUT;
570 28 fpi_ssm_jump_to_state (ssm, CAPTURE_WAIT_FINGER);
571 }
572 else
573 {
574 fpi_ssm_next_state (ssm);
575 }
576 break;
577 }
578 90 }
579
580 static void
581 2 capture_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
582 {
583 2 FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
584 2 FpiDeviceElan *self = FPI_DEVICE_ELAN (_dev);
585
586 2 G_DEBUG_HERE ();
587
588 /* either max frames captured or timed out waiting for the next frame */
589
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2 if (!error ||
590 (g_error_matches (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_TIMED_OUT) &&
591 fpi_ssm_get_cur_state (ssm) == CAPTURE_WAIT_FINGER))
592 {
593
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (self->num_frames >= ELAN_MIN_FRAMES)
594 {
595 2 elan_submit_image (dev);
596 }
597 else
598 {
599 fp_dbg ("swipe too short: want >= %d frames, got %d",
600 ELAN_MIN_FRAMES, self->num_frames);
601 fpi_image_device_retry_scan (dev, FP_DEVICE_RETRY_TOO_SHORT);
602 }
603 2 g_clear_error (&error);
604 }
605 else
606 {
607 fpi_image_device_session_error (dev, error);
608 }
609
610 /* Note: We always stop capturing even if that may not be needed always.
611 * Doing this between captures appears to make it at least less likely for
612 * devices to end up in a bad state.
613 */
614 2 elan_stop_capture (self);
615 2 }
616
617 static void
618 2 elan_capture (FpiDeviceElan *self)
619 {
620 2 G_DEBUG_HERE ();
621
622 2 elan_dev_reset_state (self);
623 2 FpiSsm *ssm =
624 2 fpi_ssm_new (FP_DEVICE (self), capture_run_state, CAPTURE_NUM_STATES);
625
626 2 fpi_ssm_start (ssm, capture_complete);
627 2 }
628
629 /* this function needs to have elandev->background and elandev->last_read to be
630 * the calibration mean */
631 static int
632 3 elan_need_calibration (FpiDeviceElan *elandev)
633 {
634 3 G_DEBUG_HERE ();
635
636 3 unsigned short calib_mean =
637 3 elandev->last_read[0] * 0xff + elandev->last_read[1];
638 3 unsigned int bg_mean = 0, delta;
639 3 unsigned int frame_size = elandev->frame_width * elandev->frame_height;
640
641
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 g_assert (frame_size != 0);
642
643
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (elandev->dev_type == ELAN_0C42)
644 {
645 if (calib_mean > 5500 ||
646 calib_mean < 2500)
647 {
648 fp_dbg ("Forcing needed recalibration");
649 return 1;
650 }
651 }
652
653
2/2
✓ Branch 0 taken 21600 times.
✓ Branch 1 taken 3 times.
21603 for (int i = 0; i < frame_size; i++)
654 21600 bg_mean += elandev->background[i];
655 3 bg_mean /= frame_size;
656
657 6 delta =
658
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 bg_mean > calib_mean ? bg_mean - calib_mean : calib_mean - bg_mean;
659
660 3 fp_dbg ("calibration mean: %d, bg mean: %d, delta: %d", calib_mean,
661 bg_mean, delta);
662
663 3 return delta > ELAN_CALIBRATION_MAX_DELTA ? 1 : 0;
664 }
665
666 enum calibrate_states {
667 CALIBRATE_GET_BACKGROUND,
668 CALIBRATE_SAVE_BACKGROUND,
669 CALIBRATE_GET_MEAN,
670 CALIBRATE_CHECK_NEEDED,
671 CALIBRATE_GET_STATUS,
672 CALIBRATE_CHECK_STATUS,
673 CALIBRATE_REPEAT_STATUS,
674 CALIBRATE_NUM_STATES,
675 };
676
677 static gboolean
678 3 elan_supports_calibration (FpiDeviceElan *elandev)
679 {
680 3 if (elandev->dev_type == ELAN_0C42)
681 return TRUE;
682
683 3 return elandev->fw_ver >= ELAN_MIN_CALIBRATION_FW;
684 }
685
686 static void
687 29 calibrate_run_state (FpiSsm *ssm, FpDevice *dev)
688 {
689 29 FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
690
691 29 G_DEBUG_HERE ();
692
693
7/8
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 6 times.
✓ Branch 6 taken 6 times.
✓ Branch 7 taken 5 times.
✗ Branch 8 not taken.
29 switch (fpi_ssm_get_cur_state (ssm))
694 {
695 3 case CALIBRATE_GET_BACKGROUND:
696 3 elan_run_cmd (ssm, dev, &get_image_cmd, ELAN_CMD_TIMEOUT);
697 3 break;
698
699 3 case CALIBRATE_SAVE_BACKGROUND:
700 3 elan_save_background (self);
701
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
3 if (!elan_supports_calibration (self))
702 {
703 fp_dbg ("FW does not support calibration");
704 fpi_ssm_mark_completed (ssm);
705 }
706 else
707 {
708 3 fpi_ssm_next_state (ssm);
709 }
710 break;
711
712 3 case CALIBRATE_GET_MEAN:
713 3 elan_run_cmd (ssm, dev, &get_calib_mean_cmd, ELAN_CMD_TIMEOUT);
714 3 break;
715
716 3 case CALIBRATE_CHECK_NEEDED:
717
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 2 times.
3 if (elan_need_calibration (self))
718 {
719 1 self->calib_status = 0;
720 1 fpi_ssm_next_state (ssm);
721 }
722 else
723 {
724 2 fpi_ssm_mark_completed (ssm);
725 }
726 break;
727
728 6 case CALIBRATE_GET_STATUS:
729 6 self->calib_atts_left -= 1;
730
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (self->calib_atts_left)
731 {
732 6 elan_run_cmd (ssm, dev, &get_calib_status_cmd,
733 ELAN_CMD_TIMEOUT);
734 }
735 else
736 {
737 fp_dbg ("calibration failed");
738 fpi_ssm_mark_failed (ssm,
739 fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL,
740 "Calibration failed!"));
741 }
742 break;
743
744 6 case CALIBRATE_CHECK_STATUS:
745 /* 0x01 - retry, 0x03 - ok
746 * It appears that when reading the response soon after 0x4023 the device
747 * can return 0x03, and only after some time (up to 100 ms) the response
748 * changes to 0x01. It stays that way for some time and then changes back
749 * to 0x03. Because of this we don't just expect 0x03, we want to see 0x01
750 * first. This is to make sure that a full calibration loop has completed */
751 6 fp_dbg ("calibration status: 0x%02x", self->last_read[0]);
752
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 times.
6 if (self->calib_status == 0x01 &&
753
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 4 times.
5 self->last_read[0] == 0x03)
754 {
755 1 self->calib_status = 0x03;
756 1 fpi_ssm_jump_to_state (ssm, CALIBRATE_GET_BACKGROUND);
757 }
758 else
759 {
760
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 4 times.
5 if (self->calib_status == 0x00 &&
761
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 self->last_read[0] == 0x01)
762 1 self->calib_status = 0x01;
763 5 fpi_ssm_next_state_delayed (ssm, 50);
764 }
765 break;
766
767 5 case CALIBRATE_REPEAT_STATUS:
768 5 fpi_ssm_jump_to_state (ssm, CALIBRATE_GET_STATUS);
769 5 break;
770 }
771 29 }
772
773 static void
774 2 calibrate_complete (FpiSsm *ssm, FpDevice *dev, GError *error)
775 {
776 2 G_DEBUG_HERE ();
777
778
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (error)
779 {
780 fpi_image_device_session_error (FP_IMAGE_DEVICE (dev), error);
781 elan_stop_capture (FPI_DEVICE_ELAN (dev));
782 }
783 else
784 {
785 2 elan_capture (FPI_DEVICE_ELAN (dev));
786 }
787 2 }
788
789 static void
790 2 elan_calibrate (FpiDeviceElan *self)
791 {
792 2 G_DEBUG_HERE ();
793
794 2 elan_dev_reset_state (self);
795
796
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 g_return_if_fail (!self->active);
797 2 self->active = TRUE;
798 2 self->calib_atts_left = ELAN_CALIBRATION_ATTEMPTS;
799
800 2 FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (self), calibrate_run_state,
801 CALIBRATE_NUM_STATES);
802
803 2 fpi_ssm_start (ssm, calibrate_complete);
804 }
805
806 enum activate_states {
807 ACTIVATE_GET_FW_VER,
808 ACTIVATE_SET_FW_VER,
809 ACTIVATE_GET_SENSOR_DIM,
810 ACTIVATE_SET_SENSOR_DIM,
811 ACTIVATE_CMD_1,
812 ACTIVATE_NUM_STATES,
813 };
814
815 static void
816 10 activate_run_state (FpiSsm *ssm, FpDevice *dev)
817 {
818 10 FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
819
820 10 G_DEBUG_HERE ();
821
822
5/6
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
10 switch (fpi_ssm_get_cur_state (ssm))
823 {
824 2 case ACTIVATE_GET_FW_VER:
825 2 elan_run_cmd (ssm, dev, &get_fw_ver_cmd, ELAN_CMD_TIMEOUT);
826 2 break;
827
828 2 case ACTIVATE_SET_FW_VER:
829 2 self->fw_ver =
830 2 (self->last_read[0] << 8 | self->last_read[1]);
831 2 fp_dbg ("FW ver 0x%04hx", self->fw_ver);
832 2 fpi_ssm_next_state (ssm);
833 2 break;
834
835 2 case ACTIVATE_GET_SENSOR_DIM:
836 2 elan_run_cmd (ssm, dev, &get_sensor_dim_cmd, ELAN_CMD_TIMEOUT);
837 2 break;
838
839 2 case ACTIVATE_SET_SENSOR_DIM:
840 /* see elan_save_frame for details */
841
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (self->dev_type & ELAN_NOT_ROTATED)
842 {
843 self->frame_width = self->last_read[0];
844 self->frame_height = self->raw_frame_height =
845 self->last_read[2];
846 }
847 else
848 {
849 2 self->frame_width = self->last_read[2];
850 2 self->frame_height = self->raw_frame_height =
851 2 self->last_read[0];
852 }
853 /* Work-around sensors returning the sizes as zero-based index
854 * rather than the number of pixels. */
855
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if ((self->frame_width % 2 == 1) &&
856 (self->frame_height % 2 == 1))
857 {
858 self->frame_width++;
859 self->frame_height++;
860 self->raw_frame_height = self->frame_height;
861 }
862
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (self->frame_height > ELAN_MAX_FRAME_HEIGHT)
863 2 self->frame_height = ELAN_MAX_FRAME_HEIGHT;
864 2 fp_dbg ("sensor dimensions, WxH: %dx%d", self->frame_width,
865 self->raw_frame_height);
866 2 fpi_ssm_next_state (ssm);
867 2 break;
868
869 2 case ACTIVATE_CMD_1:
870 /* TODO: find out what this does, if we need it */
871 2 elan_run_cmd (ssm, dev, &activate_cmd_1, ELAN_CMD_TIMEOUT);
872 2 break;
873 }
874 10 }
875
876 static void
877 2 activate_complete (FpiSsm *ssm, FpDevice *dev, GError *error)
878 {
879 2 FpImageDevice *idev = FP_IMAGE_DEVICE (dev);
880
881 2 G_DEBUG_HERE ();
882
883 2 fpi_image_device_activate_complete (idev, error);
884
885 2 }
886
887 static void
888 2 elan_activate (FpImageDevice *dev)
889 {
890 2 FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
891
892 2 G_DEBUG_HERE ();
893 2 elan_dev_reset_state (self);
894
895 2 FpiSsm *ssm =
896 2 fpi_ssm_new (FP_DEVICE (dev), activate_run_state,
897 ACTIVATE_NUM_STATES);
898
899 2 fpi_ssm_start (ssm, activate_complete);
900 2 }
901
902 static void
903 2 dev_init (FpImageDevice *dev)
904 {
905 2 GError *error = NULL;
906 2 FpiDeviceElan *self;
907
908 2 G_DEBUG_HERE ();
909
910
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 if (!g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error))
911 {
912 fpi_image_device_open_complete (dev, error);
913 return;
914 }
915
916 2 self = FPI_DEVICE_ELAN (dev);
917
918 /* common params */
919 2 self->dev_type = fpi_device_get_driver_data (FP_DEVICE (dev));
920 2 self->background = NULL;
921 2 self->process_frame = elan_process_frame_thirds;
922
923
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 switch (self->dev_type)
924 {
925 case ELAN_0907:
926 self->process_frame = elan_process_frame_linear;
927 break;
928 }
929
930 2 fpi_image_device_open_complete (dev, NULL);
931 }
932
933 static void
934 2 dev_deinit (FpImageDevice *dev)
935 {
936 2 GError *error = NULL;
937 2 FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
938
939 2 G_DEBUG_HERE ();
940
941 2 elan_dev_reset_state (self);
942 2 g_free (self->background);
943 2 g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)),
944 0, 0, &error);
945 2 fpi_image_device_close_complete (dev, error);
946 2 }
947
948 static void
949 2 dev_activate (FpImageDevice *dev)
950 {
951 2 G_DEBUG_HERE ();
952 2 elan_activate (dev);
953 2 }
954
955 static void
956 16 dev_change_state (FpImageDevice *dev, FpiImageDeviceState state)
957 {
958 16 FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
959
960 16 G_DEBUG_HERE ();
961
962 /* Note: We always calibrate even if that may not be needed always.
963 * Doing this for each capture appears to make it at least less likely for
964 * devices to end up in a bad state.
965 */
966
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 if (state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON)
967 2 elan_calibrate (self);
968 16 }
969
970 static void
971 2 dev_deactivate (FpImageDevice *dev)
972 {
973 2 FpiDeviceElan *self = FPI_DEVICE_ELAN (dev);
974
975 2 G_DEBUG_HERE ();
976
977
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (!self->active)
978 /* The device is inactive already, complete the operation immediately. */
979 2 fpi_image_device_deactivate_complete (dev, NULL);
980 else
981 /* The device is not yet inactive, flag that we are deactivating (and
982 * need to signal back deactivation).
983 * Note that any running capture will be cancelled already if needed. */
984 self->deactivating = TRUE;
985 2 }
986
987 static void
988 2 fpi_device_elan_init (FpiDeviceElan *self)
989 {
990 2 }
991 static void
992 120 fpi_device_elan_class_init (FpiDeviceElanClass *klass)
993 {
994 120 FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
995 120 FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
996
997 120 dev_class->id = "elan";
998 120 dev_class->full_name = "ElanTech Fingerprint Sensor";
999 120 dev_class->type = FP_DEVICE_TYPE_USB;
1000 120 dev_class->id_table = elan_id_table;
1001 120 dev_class->scan_type = FP_SCAN_TYPE_SWIPE;
1002
1003 120 img_class->img_open = dev_init;
1004 120 img_class->img_close = dev_deinit;
1005 120 img_class->activate = dev_activate;
1006 120 img_class->deactivate = dev_deactivate;
1007 120 img_class->change_state = dev_change_state;
1008
1009 120 img_class->bz3_threshold = 24;
1010 }
1011