GCC Code Coverage Report


Directory: ./
File: libfprint/drivers/aes2550.c
Date: 2024-05-04 14:54:39
Exec Total Coverage
Lines: 15 227 6.6%
Functions: 3 21 14.3%
Branches: 4 57 7.0%

Line Branch Exec Source
1 /*
2 * AuthenTec AES2550/AES2810 driver for libfprint
3 * Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org>
4 * Copyright (C) 2007 Cyrille Bagard
5 * Copyright (C) 2007-2012 Vasily Khoruzhick
6 *
7 * Based on AES2501 driver
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24 #define FP_COMPONENT "aes2550"
25
26 #include "drivers_api.h"
27 #include "aes2550.h"
28 #include "aeslib.h"
29
30 static void start_capture (FpImageDevice *dev);
31 static void complete_deactivation (FpImageDevice *dev);
32
33 #define EP_IN (1 | FPI_USB_ENDPOINT_IN)
34 #define EP_OUT (2 | FPI_USB_ENDPOINT_OUT)
35 #define BULK_TIMEOUT 4000
36
37 /*
38 * The AES2550 is an imaging device using a swipe-type sensor. It samples
39 * the finger at preprogrammed intervals, sending a 192x16 frame to the
40 * computer.
41 * Unless the user is scanning their finger unreasonably fast, the frames
42 * *will* overlap. The implementation below detects this overlap and produces
43 * a contiguous image as the end result.
44 * The fact that the user determines the length of the swipe (and hence the
45 * number of useful frames) and also the fact that overlap varies means that
46 * images returned from this driver vary in height.
47 */
48
49 #define FRAME_WIDTH 192
50 #define FRAME_HEIGHT 8
51 #define FRAME_SIZE (FRAME_WIDTH * FRAME_HEIGHT)
52 #define IMAGE_WIDTH (FRAME_WIDTH + (FRAME_WIDTH / 2))
53
54 struct _FpiDeviceAes2550
55 {
56 FpImageDevice parent;
57
58 GSList *strips;
59 size_t strips_len;
60 gboolean deactivating;
61 int heartbeat_cnt;
62 };
63 G_DECLARE_FINAL_TYPE (FpiDeviceAes2550, fpi_device_aes2550, FPI, DEVICE_AES2550,
64 FpImageDevice);
65
4/5
✓ Branch 0 taken 117 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 117 times.
✓ Branch 3 taken 117 times.
✗ Branch 4 not taken.
750 G_DEFINE_TYPE (FpiDeviceAes2550, fpi_device_aes2550, FP_TYPE_IMAGE_DEVICE);
66
67 static struct fpi_frame_asmbl_ctx assembling_ctx = {
68 .frame_width = FRAME_WIDTH,
69 .frame_height = FRAME_HEIGHT,
70 .image_width = IMAGE_WIDTH,
71 .get_pixel = aes_get_pixel,
72 };
73
74 /****** FINGER PRESENCE DETECTION ******/
75
76 static unsigned char finger_det_reqs[] = {
77 0x80, AES2550_REG80_MASTER_RESET,
78 0x95, (8 << AES2550_REG95_COL_SCANNED_OFS) | (1 << AES2550_REG95_EPIX_AVG_OFS),
79 0xad, 0x00,
80 0xbd, (0 << AES2550_REGBD_LPO_IN_15_8_OFS),
81 0xbe, (0 << AES2550_REGBE_LPO_IN_7_0_OFS),
82 0xcf, AES2550_REGCF_INTERFERENCE_CHK_EN,
83 AES2550_CMD_HEARTBEAT, 0x00, 0x01, 0x00, /* Heart beat off */
84 AES2550_CMD_RUN_FD,
85 };
86
87 static void start_finger_detection (FpImageDevice *dev);
88
89 static void
90 finger_det_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
91 gpointer user_data, GError *error)
92 {
93 FpImageDevice *dev = FP_IMAGE_DEVICE (device);
94 unsigned char *data = transfer->buffer;
95
96 if (error)
97 {
98 fpi_image_device_session_error (FP_IMAGE_DEVICE (device), error);
99 return;
100 }
101
102 fp_dbg ("transfer completed, len: %.4x, data: %.2x %.2x",
103 (gint) transfer->actual_length, (int) data[0], (int) data[1]);
104
105 /* Check if we got 2 bytes, reg address 0x83 and its value */
106 if ((transfer->actual_length >= 2) && (data[0] == 0x83) && (data[1] & AES2550_REG83_FINGER_PRESENT))
107 {
108 /* finger present, start capturing */
109 fpi_image_device_report_finger_status (dev, TRUE);
110 start_capture (dev);
111 }
112 else
113 {
114 /* no finger, poll for a new histogram */
115 start_finger_detection (dev);
116 }
117 }
118
119 static void
120 finger_det_reqs_cb (FpiUsbTransfer *t, FpDevice *device,
121 gpointer user_data, GError *error)
122 {
123 FpiUsbTransfer *transfer;
124 FpImageDevice *dev = FP_IMAGE_DEVICE (device);
125
126 if (error)
127 {
128 fpi_image_device_session_error (dev, error);
129 return;
130 }
131
132 transfer = fpi_usb_transfer_new (device);
133 /* 2 bytes of result */
134 fpi_usb_transfer_fill_bulk (transfer, EP_IN, AES2550_EP_IN_BUF_SIZE);
135 fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
136 finger_det_data_cb, NULL);
137 }
138
139 static void
140 start_finger_detection (FpImageDevice *dev)
141 {
142 FpiDeviceAes2550 *self = FPI_DEVICE_AES2550 (dev);
143 FpiUsbTransfer *transfer;
144
145 G_DEBUG_HERE ();
146
147 if (self->deactivating)
148 {
149 complete_deactivation (dev);
150 return;
151 }
152
153 transfer = fpi_usb_transfer_new (FP_DEVICE (dev));
154 transfer->short_is_error = TRUE;
155 fpi_usb_transfer_fill_bulk_full (transfer, EP_OUT, finger_det_reqs,
156 sizeof (finger_det_reqs), NULL);
157 fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
158 finger_det_reqs_cb, NULL);
159 }
160
161 /****** CAPTURE ******/
162
163 static unsigned char capture_reqs[] = {
164 0x80, AES2550_REG80_MASTER_RESET,
165 0x80, (1 << AES2550_REG80_SENSOR_MODE_OFS) | (AES2550_REG80_HGC_ENABLE),
166 0x85, AES2550_REG85_FLUSH_PER_FRAME,
167 0x8f, AES2550_REG8F_AUTH_DISABLE | AES2550_REG8F_EHISTO_DISABLE,
168 0xbf, AES2550_REGBF_RSR_DIR_UPDOWN_MOTION | AES2550_REGBF_RSR_LEVEL_SUPER_RSR,
169 0xcf, (3 << AES2550_REGCF_INTERFERENCE_AVG_OFFS) | AES2550_REGCF_INTERFERENCE_AVG_EN,
170 0xdc, (1 << AES2550_REGDC_BP_NUM_REF_SWEEP_OFS),
171 AES2550_CMD_HEARTBEAT, 0x00, 0x01, 0x03, /* Heart beat cmd, 3 * 16 cycles without sending image */
172 AES2550_CMD_GET_ENROLL_IMG,
173 };
174
175 static unsigned char capture_set_idle_reqs[] = {
176 0x80, AES2550_REG80_MASTER_RESET,
177 AES2550_CMD_HEARTBEAT, 0x00, 0x01, 0x00, /* Heart beat off */
178 AES2550_CMD_SET_IDLE_MODE,
179 };
180
181 enum capture_states {
182 CAPTURE_WRITE_REQS,
183 CAPTURE_READ_DATA,
184 CAPTURE_SET_IDLE,
185 CAPTURE_NUM_STATES,
186 };
187
188 /* Returns number of processed bytes */
189 static gboolean
190 process_strip_data (FpiSsm *ssm, FpImageDevice *dev,
191 unsigned char *data)
192 {
193 unsigned char *stripdata;
194 FpiDeviceAes2550 *self = FPI_DEVICE_AES2550 (dev);
195 struct fpi_frame *stripe;
196 int len;
197
198 if (data[0] != AES2550_EDATA_MAGIC)
199 {
200 fp_dbg ("Bogus magic: %.2x", (int) (data[0]));
201 return FALSE;
202 }
203 len = data[1] * 256 + data[2];
204 if (len != (AES2550_STRIP_SIZE - 3))
205 fp_dbg ("Bogus frame len: %.4x", len);
206 stripe = g_malloc0 (FRAME_WIDTH * FRAME_HEIGHT / 2 + sizeof (struct fpi_frame)); /* 4 bits per pixel */
207 stripe->delta_x = (int8_t) data[6];
208 stripe->delta_y = -(int8_t) data[7];
209 stripdata = stripe->data;
210 memcpy (stripdata, data + 33, FRAME_WIDTH * FRAME_HEIGHT / 2);
211 self->strips = g_slist_prepend (self->strips, stripe);
212 self->strips_len++;
213
214 fp_dbg ("deltas: %dx%d", stripe->delta_x, stripe->delta_y);
215
216 return TRUE;
217 }
218
219 static void
220 capture_set_idle_reqs_cb (FpiUsbTransfer *transfer,
221 FpDevice *device, gpointer user_data,
222 GError *error)
223 {
224 FpImageDevice *dev = FP_IMAGE_DEVICE (device);
225 FpiDeviceAes2550 *self = FPI_DEVICE_AES2550 (dev);
226
227 if (!error && self->strips_len)
228 {
229 FpImage *img;
230
231 self->strips = g_slist_reverse (self->strips);
232 img = fpi_assemble_frames (&assembling_ctx, self->strips);
233 img->flags |= FPI_IMAGE_PARTIAL;
234 g_slist_free_full (self->strips, g_free);
235 self->strips = NULL;
236 self->strips_len = 0;
237 fpi_image_device_image_captured (dev, img);
238 fpi_image_device_report_finger_status (dev, FALSE);
239 /* marking machine complete will re-trigger finger detection loop */
240 fpi_ssm_mark_completed (transfer->ssm);
241 }
242 else
243 {
244 if (error)
245 fpi_ssm_mark_failed (transfer->ssm, error);
246 else
247 fpi_ssm_mark_failed (transfer->ssm,
248 fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
249 }
250 }
251
252 static void
253 capture_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
254 gpointer user_data, GError *error)
255 {
256 FpImageDevice *dev = FP_IMAGE_DEVICE (device);
257 FpiDeviceAes2550 *self = FPI_DEVICE_AES2550 (dev);
258 unsigned char *data = transfer->buffer;
259
260 if (error)
261 {
262 fpi_ssm_mark_failed (transfer->ssm, error);
263 return;
264 }
265
266 fp_dbg ("request completed, len: %.4x", (gint) transfer->actual_length);
267 if (transfer->actual_length >= 2)
268 fp_dbg ("data: %.2x %.2x", (int) data[0], (int) data[1]);
269
270 switch (transfer->actual_length)
271 {
272 case AES2550_STRIP_SIZE:
273 if (!process_strip_data (transfer->ssm, dev, data))
274 {
275 fp_dbg ("Processing strip data failed");
276 fpi_ssm_mark_failed (transfer->ssm,
277 fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
278 return;
279 }
280 self->heartbeat_cnt = 0;
281 fpi_ssm_jump_to_state (transfer->ssm, CAPTURE_READ_DATA);
282 break;
283
284 case AES2550_HEARTBEAT_SIZE:
285 if (data[0] == AES2550_HEARTBEAT_MAGIC)
286 {
287 /* No data for a long time => finger was removed or there's no movement */
288 self->heartbeat_cnt++;
289 if (self->heartbeat_cnt == 3)
290 {
291 /* Got 3 heartbeat message, that's enough to consider that finger was removed,
292 * assemble image and submit it to the library */
293 fp_dbg ("Got 3 heartbeats => finger removed");
294 fpi_ssm_next_state (transfer->ssm);
295 }
296 else
297 {
298 fpi_ssm_jump_to_state (transfer->ssm,
299 CAPTURE_READ_DATA);
300 }
301 }
302 break;
303
304 default:
305 fp_dbg ("Short frame %d, skip",
306 (gint) transfer->actual_length);
307 fpi_ssm_jump_to_state (transfer->ssm, CAPTURE_READ_DATA);
308 break;
309 }
310 }
311
312 static void
313 capture_run_state (FpiSsm *ssm, FpDevice *dev)
314 {
315 switch (fpi_ssm_get_cur_state (ssm))
316 {
317 case CAPTURE_WRITE_REQS:
318 {
319 FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
320
321 fpi_usb_transfer_fill_bulk_full (transfer, EP_OUT, capture_reqs,
322 sizeof (capture_reqs), NULL);
323 transfer->ssm = ssm;
324 transfer->short_is_error = TRUE;
325 fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
326 fpi_ssm_usb_transfer_cb, NULL);
327 }
328 break;
329
330 case CAPTURE_READ_DATA:
331 {
332 FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
333
334 fpi_usb_transfer_fill_bulk (transfer, EP_IN, AES2550_EP_IN_BUF_SIZE);
335 transfer->ssm = ssm;
336 fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
337 capture_read_data_cb, NULL);
338 }
339 break;
340
341 case CAPTURE_SET_IDLE:
342 {
343 FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
344
345 fpi_usb_transfer_fill_bulk_full (transfer, EP_OUT,
346 capture_set_idle_reqs,
347 sizeof (capture_set_idle_reqs),
348 NULL);
349 transfer->ssm = ssm;
350 transfer->short_is_error = TRUE;
351 fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
352 capture_set_idle_reqs_cb, NULL);
353 }
354 break;
355 }
356 ;
357 }
358
359 static void
360 capture_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
361 {
362 FpiDeviceAes2550 *self = FPI_DEVICE_AES2550 (_dev);
363 FpImageDevice *dev = FP_IMAGE_DEVICE (self);
364
365 fp_dbg ("Capture completed");
366
367 if (self->deactivating)
368 {
369 complete_deactivation (dev);
370 g_clear_pointer (&error, g_error_free);
371 }
372 else if (error)
373 {
374 fpi_image_device_session_error (dev, error);
375 }
376 else
377 {
378 start_finger_detection (dev);
379 }
380 }
381
382 static void
383 start_capture (FpImageDevice *dev)
384 {
385 FpiDeviceAes2550 *self = FPI_DEVICE_AES2550 (dev);
386 FpiSsm *ssm;
387
388 if (self->deactivating)
389 {
390 complete_deactivation (dev);
391 return;
392 }
393
394 self->heartbeat_cnt = 0;
395 ssm = fpi_ssm_new (FP_DEVICE (dev), capture_run_state, CAPTURE_NUM_STATES);
396 G_DEBUG_HERE ();
397 fpi_ssm_start (ssm, capture_sm_complete);
398 }
399
400 /****** INITIALIZATION/DEINITIALIZATION ******/
401
402 static unsigned char init_reqs[] = {
403 0x80, AES2550_REG80_MASTER_RESET, /* Master reset */
404 0x80, (1 << AES2550_REG80_SENSOR_MODE_OFS) | (AES2550_REG80_FORCE_FINGER_PRESENT),
405 0x85, AES2550_REG85_FLUSH_PER_FRAME,
406 0xa8, AES2550_REGA8_DIG_BIT_EN,
407 0x81, AES2550_REG81_NSHOT,
408 };
409
410 static unsigned char calibrate_reqs[] = {
411 0x80, AES2550_REG80_MASTER_RESET, /* Master reset */
412 AES2550_CMD_CALIBRATE,
413 AES2550_CMD_READ_CALIBRATION_DATA,
414 };
415
416 enum activate_states {
417 WRITE_INIT,
418 READ_DATA,
419 CALIBRATE,
420 READ_CALIB_TABLE,
421 ACTIVATE_NUM_STATES,
422 };
423
424 /* TODO: use calibration table, datasheet is rather terse on that
425 * need more info for implementation */
426 static void
427 calibrate_read_data_cb (FpiUsbTransfer *transfer, FpDevice *device,
428 gpointer user_data, GError *error)
429 {
430 fpi_ssm_usb_transfer_cb (transfer, device, user_data, error);
431 }
432
433 static void
434 activate_run_state (FpiSsm *ssm, FpDevice *dev)
435 {
436 switch (fpi_ssm_get_cur_state (ssm))
437 {
438 case WRITE_INIT:
439 {
440 FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
441
442 fpi_usb_transfer_fill_bulk_full (transfer, EP_OUT, init_reqs,
443 sizeof (init_reqs), NULL);
444 transfer->ssm = ssm;
445 transfer->short_is_error = TRUE;
446 fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
447 fpi_ssm_usb_transfer_cb, NULL);
448 }
449 break;
450
451 case READ_DATA:
452 {
453 FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
454
455 fpi_usb_transfer_fill_bulk (transfer, EP_IN, AES2550_EP_IN_BUF_SIZE);
456 transfer->ssm = ssm;
457 fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
458 fpi_ssm_usb_transfer_cb, NULL);
459 }
460 break;
461
462 case CALIBRATE:
463 {
464 FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
465
466 fpi_usb_transfer_fill_bulk_full (transfer, EP_OUT,
467 calibrate_reqs,
468 sizeof (calibrate_reqs), NULL);
469 transfer->ssm = ssm;
470 transfer->short_is_error = TRUE;
471 fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
472 fpi_ssm_usb_transfer_cb, NULL);
473 }
474 break;
475
476 case READ_CALIB_TABLE:
477 {
478 FpiUsbTransfer *transfer = fpi_usb_transfer_new (dev);
479
480 fpi_usb_transfer_fill_bulk (transfer, EP_IN, AES2550_EP_IN_BUF_SIZE);
481 transfer->ssm = ssm;
482 fpi_usb_transfer_submit (transfer, BULK_TIMEOUT, NULL,
483 calibrate_read_data_cb, NULL);
484 }
485 break;
486 }
487 }
488
489 static void
490 activate_sm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
491 {
492 FpImageDevice *dev = FP_IMAGE_DEVICE (_dev);
493
494 fpi_image_device_activate_complete (dev, error);
495
496 if (!error)
497 start_finger_detection (dev);
498 }
499
500 static void
501 dev_activate (FpImageDevice *dev)
502 {
503 FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (dev), activate_run_state,
504 ACTIVATE_NUM_STATES);
505
506 fpi_ssm_start (ssm, activate_sm_complete);
507 }
508
509 static void
510 dev_deactivate (FpImageDevice *dev)
511 {
512 FpiDeviceAes2550 *self = FPI_DEVICE_AES2550 (dev);
513
514 self->deactivating = TRUE;
515 }
516
517 static void
518 complete_deactivation (FpImageDevice *dev)
519 {
520 FpiDeviceAes2550 *self = FPI_DEVICE_AES2550 (dev);
521
522 G_DEBUG_HERE ();
523
524 self->deactivating = FALSE;
525 g_slist_free (self->strips);
526 self->strips = NULL;
527 self->strips_len = 0;
528 fpi_image_device_deactivate_complete (dev, NULL);
529 }
530
531 static void
532 dev_init (FpImageDevice *dev)
533 {
534 GError *error = NULL;
535
536 /* TODO check that device has endpoints we're using */
537
538 g_usb_device_claim_interface (fpi_device_get_usb_device (FP_DEVICE (dev)), 0, 0, &error);
539
540 fpi_image_device_open_complete (dev, error);
541 }
542
543 static void
544 dev_deinit (FpImageDevice *dev)
545 {
546 GError *error = NULL;
547
548 g_usb_device_release_interface (fpi_device_get_usb_device (FP_DEVICE (dev)),
549 0, 0, &error);
550 fpi_image_device_close_complete (dev, error);
551 }
552
553 static const FpIdEntry id_table[] = {
554 { .vid = 0x08ff, .pid = 0x2550, },/* AES2550 */
555 { .vid = 0x08ff, .pid = 0x2810, },/* AES2810 */
556 { .vid = 0, .pid = 0, .driver_data = 0 },
557 };
558
559 static void
560 fpi_device_aes2550_init (FpiDeviceAes2550 *self)
561 {
562 }
563 static void
564 117 fpi_device_aes2550_class_init (FpiDeviceAes2550Class *klass)
565 {
566 117 FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
567 117 FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass);
568
569 117 dev_class->id = "aes2550";
570 117 dev_class->full_name = "AuthenTec AES2550/AES2810";
571 117 dev_class->type = FP_DEVICE_TYPE_USB;
572 117 dev_class->id_table = id_table;
573 117 dev_class->scan_type = FP_SCAN_TYPE_SWIPE;
574
575 117 img_class->img_open = dev_init;
576 117 img_class->img_close = dev_deinit;
577 117 img_class->activate = dev_activate;
578 117 img_class->deactivate = dev_deactivate;
579
580 117 img_class->img_width = FRAME_WIDTH + FRAME_WIDTH / 2;
581 117 img_class->img_height = -1;
582 }
583