v0.0.1 release
[libfprint.git] / libfprint / drivers / aes2501.c
blob3334df7eeafe2d9ee4a3eaa7f7ae3b8faa188648
1 /*
2 * AuthenTec AES2501 driver for libfprint
3 * Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
4 * Copyright (C) 2007 Cyrille Bagard
5 * Copyright (C) 2007 Vasily Khoruzhick
7 * Based on code from http://home.gna.org/aes2501, relicensed with permission
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.
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.
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
24 #define FP_COMPONENT "aes2501"
26 #include <errno.h>
27 #include <string.h>
29 #include <usb.h>
31 #include <fp_internal.h>
32 #include "aes2501.h"
34 /* FIXME these need checking */
35 #define EP_IN (1 | USB_ENDPOINT_IN)
36 #define EP_OUT (2 | USB_ENDPOINT_OUT)
38 #define BULK_TIMEOUT 4000
41 * The AES2501 is an imaging device using a swipe-type sensor. It samples
42 * the finger at preprogrammed intervals, sending a 192x16 frame to the
43 * computer.
44 * Unless the user is scanning their finger unreasonably fast, the frames
45 * *will* overlap. The implementation below detects this overlap and produces
46 * a contiguous image as the end result.
47 * The fact that the user determines the length of the swipe (and hence the
48 * number of useful frames) and also the fact that overlap varies means that
49 * images returned from this driver vary in height.
52 #define FRAME_WIDTH 192
53 #define FRAME_HEIGHT 16
54 #define FRAME_SIZE (FRAME_WIDTH * FRAME_HEIGHT)
55 /* maximum number of frames to read during a scan */
56 /* FIXME reduce substantially */
57 #define MAX_FRAMES 150
59 struct aes2501_regwrite {
60 unsigned char reg;
61 unsigned char value;
64 static int write_reg(struct fp_img_dev *dev, unsigned char reg,
65 unsigned char value)
67 unsigned char data[] = { reg, value };
68 int r;
70 fp_dbg("%02x=%02x", reg, value);
71 r = usb_bulk_write(dev->udev, EP_OUT, data, sizeof(data), BULK_TIMEOUT);
72 if (r < 0) {
73 fp_err("bulk write error %d", r);
74 return r;
75 } else if (r < sizeof(data)) {
76 fp_err("unexpected short write %d/%d", r, sizeof(data));
77 return -EIO;
80 return 0;
83 static int write_regv(struct fp_img_dev *dev, struct aes2501_regwrite *regs,
84 unsigned int num)
86 unsigned int i;
87 int r;
89 /* FIXME: could combine multiple writes into a single transaction */
91 for (i = 0; i < num; i++) {
92 r = write_reg(dev, regs[i].reg, regs[i].value);
93 if (r < 0)
94 return r;
96 return 0;
99 static int read_data(struct fp_img_dev *dev, unsigned char *data, size_t len)
101 int r;
102 fp_dbg("len=%zd", len);
104 r = usb_bulk_read(dev->udev, EP_IN, data, len, BULK_TIMEOUT);
105 if (r < 0) {
106 fp_err("bulk read error %d", r);
107 return r;
108 } else if (r < len) {
109 fp_err("unexpected short read %d/%zd", r, len);
110 return -EIO;
112 return 0;
115 static int read_regs(struct fp_img_dev *dev, unsigned char *data)
117 int r;
118 fp_dbg("");
120 r = write_reg(dev, AES2501_REG_CTRL2, AES2501_CTRL2_READ_REGS);
121 if (r < 0)
122 return r;
124 return read_data(dev, data, 126);
127 static const struct aes2501_regwrite init_1[] = {
128 { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET },
129 { 0xb0, 0x27 }, /* Reserved? */
130 { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET },
131 { AES2501_REG_EXCITCTRL, 0x40 },
132 { 0xff, 0x00 }, /* Reserved? */
133 { 0xff, 0x00 }, /* Reserved? */
134 { 0xff, 0x00 }, /* Reserved? */
135 { 0xff, 0x00 }, /* Reserved? */
136 { 0xff, 0x00 }, /* Reserved? */
137 { 0xff, 0x00 }, /* Reserved? */
138 { 0xff, 0x00 }, /* Reserved? */
139 { 0xff, 0x00 }, /* Reserved? */
140 { 0xff, 0x00 }, /* Reserved? */
141 { 0xff, 0x00 }, /* Reserved? */
142 { 0xff, 0x00 }, /* Reserved? */
143 { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET },
144 { AES2501_REG_EXCITCTRL, 0x40 },
145 { AES2501_REG_DETCTRL,
146 AES2501_DETCTRL_DRATE_CONTINUOUS | AES2501_DETCTRL_SDELAY_31_MS },
147 { AES2501_REG_COLSCAN, AES2501_COLSCAN_SRATE_128_US },
148 { AES2501_REG_MEASDRV,
149 AES2501_MEASDRV_MDRIVE_0_325 | AES2501_MEASDRV_MEASURE_SQUARE },
150 { AES2501_REG_MEASFREQ, AES2501_MEASFREQ_2M },
151 { AES2501_REG_DEMODPHASE1, DEMODPHASE_NONE },
152 { AES2501_REG_DEMODPHASE2, DEMODPHASE_NONE },
153 { AES2501_REG_CHANGAIN,
154 AES2501_CHANGAIN_STAGE2_4X | AES2501_CHANGAIN_STAGE1_16X },
155 { AES2501_REG_ADREFHI, 0x44 },
156 { AES2501_REG_ADREFLO, 0x34 },
157 { AES2501_REG_STRTCOL, 0x16 },
158 { AES2501_REG_ENDCOL, 0x16 },
159 { AES2501_REG_DATFMT, AES2501_DATFMT_BIN_IMG | 0x08 },
160 { AES2501_REG_TREG1, 0x70 },
161 { 0xa2, 0x02 },
162 { 0xa7, 0x00 },
163 { AES2501_REG_TREGC, AES2501_TREGC_ENABLE },
164 { AES2501_REG_TREGD, 0x1a },
165 { AES2501_REG_CTRL1, AES2501_CTRL1_REG_UPDATE },
166 { AES2501_REG_CTRL2, AES2501_CTRL2_SET_ONE_SHOT },
167 { AES2501_REG_LPONT, AES2501_LPONT_MIN_VALUE },
170 static const struct aes2501_regwrite init_2[] = {
171 { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET },
172 { AES2501_REG_EXCITCTRL, 0x40 },
173 { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET },
174 { AES2501_REG_AUTOCALOFFSET, 0x41 },
175 { AES2501_REG_EXCITCTRL, 0x42 },
176 { AES2501_REG_DETCTRL, 0x53 },
177 { AES2501_REG_CTRL1, AES2501_CTRL1_REG_UPDATE },
180 static const struct aes2501_regwrite init_3[] = {
181 { 0xff, 0x00 },
182 { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET },
183 { AES2501_REG_AUTOCALOFFSET, 0x41 },
184 { AES2501_REG_EXCITCTRL, 0x42 },
185 { AES2501_REG_DETCTRL, 0x53 },
186 { AES2501_REG_CTRL1, AES2501_CTRL1_REG_UPDATE },
189 static const struct aes2501_regwrite init_4[] = {
190 { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET },
191 { AES2501_REG_EXCITCTRL, 0x40 },
192 { 0xb0, 0x27 },
193 { AES2501_REG_ENDROW, 0x0a },
194 { AES2501_REG_CTRL1, AES2501_CTRL1_REG_UPDATE },
195 { AES2501_REG_DETCTRL, 0x45 },
196 { AES2501_REG_AUTOCALOFFSET, 0x41 },
199 static const struct aes2501_regwrite init_5[] = {
200 { 0xb0, 0x27 },
201 { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET },
202 { AES2501_REG_EXCITCTRL, 0x40 },
203 { 0xff, 0x00 },
204 { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET },
205 { AES2501_REG_EXCITCTRL, 0x40 },
206 { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET },
207 { AES2501_REG_EXCITCTRL, 0x40 },
208 { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET },
209 { AES2501_REG_EXCITCTRL, 0x40 },
210 { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET },
211 { AES2501_REG_EXCITCTRL, 0x40 },
212 { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET },
213 { AES2501_REG_EXCITCTRL, 0x40 },
214 { AES2501_REG_CTRL1, AES2501_CTRL1_SCAN_RESET },
215 { AES2501_REG_CTRL1, AES2501_CTRL1_SCAN_RESET },
218 static int do_init(struct fp_img_dev *dev)
220 unsigned char buffer[128];
221 int r;
222 int i;
224 /* part 1, probably not needed */
225 r = write_regv(dev, init_1, ARRAY_SIZE(init_1));
226 if (r < 0)
227 return r;
229 r = read_data(dev, buffer, 20);
230 if (r < 0)
231 return r;
233 /* part 2 */
234 r = write_regv(dev, init_2, ARRAY_SIZE(init_2));
235 if (r < 0)
236 return r;
238 r = read_regs(dev, buffer);
239 if (r < 0)
240 return r;
242 /* part 3 */
243 fp_dbg("reg 0xaf = %x", buffer[0x5f]);
244 i = 0;
245 while (buffer[0x5f] == 0x6b) {
246 r = write_regv(dev, init_3, ARRAY_SIZE(init_3));
247 if (r < 0)
248 return r;
249 r = read_regs(dev, buffer);
250 if (r < 0)
251 return r;
252 if (++i == 13)
253 break;
256 /* part 4 */
257 r = write_regv(dev, init_4, ARRAY_SIZE(init_4));
258 if (r < 0)
259 return r;
261 /* part 5 */
262 return write_regv(dev, init_5, ARRAY_SIZE(init_5));
265 static int dev_init(struct fp_img_dev *dev, unsigned long driver_data)
267 int r;
269 r = usb_claim_interface(dev->udev, 0);
270 if (r < 0) {
271 fp_err("could not claim interface 0");
272 return r;
275 /* FIXME check endpoints */
277 return do_init(dev);
280 static void dev_exit(struct fp_img_dev *dev)
282 usb_release_interface(dev->udev, 0);
285 static const struct aes2501_regwrite finger_det_reqs[] = {
286 { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET },
287 { AES2501_REG_EXCITCTRL, 0x40 },
288 { AES2501_REG_DETCTRL,
289 AES2501_DETCTRL_DRATE_CONTINUOUS | AES2501_DETCTRL_SDELAY_31_MS },
290 { AES2501_REG_COLSCAN, AES2501_COLSCAN_SRATE_128_US },
291 { AES2501_REG_MEASDRV, AES2501_MEASDRV_MDRIVE_0_325 | AES2501_MEASDRV_MEASURE_SQUARE },
292 { AES2501_REG_MEASFREQ, AES2501_MEASFREQ_2M },
293 { AES2501_REG_DEMODPHASE1, DEMODPHASE_NONE },
294 { AES2501_REG_DEMODPHASE2, DEMODPHASE_NONE },
295 { AES2501_REG_CHANGAIN,
296 AES2501_CHANGAIN_STAGE2_4X | AES2501_CHANGAIN_STAGE1_16X },
297 { AES2501_REG_ADREFHI, 0x44 },
298 { AES2501_REG_ADREFLO, 0x34 },
299 { AES2501_REG_STRTCOL, 0x16 },
300 { AES2501_REG_ENDCOL, 0x16 },
301 { AES2501_REG_DATFMT, AES2501_DATFMT_BIN_IMG | 0x08 },
302 { AES2501_REG_TREG1, 0x70 },
303 { 0xa2, 0x02 },
304 { 0xa7, 0x00 },
305 { AES2501_REG_TREGC, AES2501_TREGC_ENABLE },
306 { AES2501_REG_TREGD, 0x1a },
307 { AES2501_REG_CTRL1, AES2501_CTRL1_REG_UPDATE },
308 { AES2501_REG_CTRL2, AES2501_CTRL2_SET_ONE_SHOT },
309 { AES2501_REG_LPONT, AES2501_LPONT_MIN_VALUE },
312 static int detect_finger(struct fp_img_dev *dev)
314 unsigned char buffer[22];
315 int r;
316 int i;
317 int sum = 0;
319 r = write_regv(dev, finger_det_reqs, ARRAY_SIZE(finger_det_reqs));
320 if (r < 0)
321 return r;
323 r = read_data(dev, buffer, 20);
324 if (r < 0)
325 return r;
327 for (i = 1; i < 9; i++)
328 sum += (buffer[i] & 0xf) + (buffer[i] >> 4);
330 return sum > 20;
333 static int await_finger_on(struct fp_img_dev *dev)
335 int r;
336 do {
337 r = detect_finger(dev);
338 } while (r == 0);
339 return (r < 0) ? r : 0;
342 /* Read the value of a specific register from a register dump */
343 static int regval_from_dump(unsigned char *data, uint8_t target)
345 if (*data != FIRST_AES2501_REG) {
346 fp_err("not a register dump");
347 return -EILSEQ;
350 if (!(FIRST_AES2501_REG <= target && target <= LAST_AES2501_REG)) {
351 fp_err("out of range");
352 return -EINVAL;
355 target -= FIRST_AES2501_REG;
356 target *= 2;
357 return data[target + 1];
360 static int sum_histogram_values(unsigned char *data, uint8_t threshold)
362 int r = 0;
363 int i;
364 uint16_t *histogram = (uint16_t *)(data + 1);
366 if (*data != 0xde)
367 return -EILSEQ;
369 if (threshold > 0x0f)
370 return -EINVAL;
372 /* FIXME endianness */
373 for (i = threshold; i < 16; i++)
374 r += histogram[i];
376 return r;
379 /* find overlapping parts of frames */
380 static unsigned int find_overlap(unsigned char *first_frame,
381 unsigned char *second_frame)
383 unsigned int dy;
384 unsigned int min_error = 255 * FRAME_SIZE;
385 unsigned int not_overlapped_height = 0;
386 for (dy = 0; dy < FRAME_HEIGHT; dy++) {
387 /* Calculating difference (error) between parts of frames */
388 unsigned int i;
389 unsigned int error = 0;
390 for (i = 0; i < FRAME_WIDTH * (FRAME_HEIGHT - dy); i++) {
391 /* Using ? operator to avoid abs function */
392 error += first_frame[i] > second_frame[i] ?
393 (first_frame[i] - second_frame[i]) :
394 (second_frame[i] - first_frame[i]);
397 /* Normalize error */
398 error *= 15;
399 error /= i;
400 if (error < min_error) {
401 min_error = error;
402 not_overlapped_height = dy;
404 first_frame += FRAME_WIDTH;
407 return not_overlapped_height;
410 /* assemble a series of frames into a single image */
411 static unsigned int assemble(unsigned char *input, unsigned char *output,
412 int num_strips)
414 uint8_t *assembled = output;
415 int frame;
416 uint32_t image_height = FRAME_HEIGHT;
418 if (num_strips < 1)
419 return 0;
421 /* Rotating given data by 90 degrees
422 * Taken from document describing aes2501 image format
423 * TODO: move reversing detection here */
425 for (frame = 0; frame < num_strips; frame++) {
426 int column;
427 for (column = 0; column < FRAME_WIDTH; column++) {
428 int row;
429 for (row = 0; row < (FRAME_HEIGHT / 2); row++) {
430 output[FRAME_WIDTH * ( 2 * row) + column] = *input & 0x0F;
431 output[FRAME_WIDTH * ( 2 * row + 1) + column] = *input >> 4;
432 input++;
436 output += FRAME_SIZE;
439 /* Detecting where frames overlaped */
440 output = assembled;
441 for (frame = 1; frame < num_strips; frame++) {
442 int not_overlapped;
444 output += FRAME_SIZE;
445 not_overlapped = find_overlap(assembled, output);
446 image_height += not_overlapped;
447 assembled += FRAME_WIDTH * not_overlapped;
448 memcpy(assembled, output, FRAME_SIZE);
450 return image_height;
453 static const struct aes2501_regwrite capture_reqs_1[] = {
454 { AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET },
455 { AES2501_REG_EXCITCTRL, 0x40 },
456 { AES2501_REG_DETCTRL,
457 AES2501_DETCTRL_SDELAY_31_MS | AES2501_DETCTRL_DRATE_CONTINUOUS },
458 { AES2501_REG_COLSCAN, AES2501_COLSCAN_SRATE_128_US },
459 { AES2501_REG_DEMODPHASE2, 0x7c },
460 { AES2501_REG_MEASDRV,
461 AES2501_MEASDRV_MEASURE_SQUARE | AES2501_MEASDRV_MDRIVE_0_325 },
462 { AES2501_REG_DEMODPHASE1, 0x24 },
463 { AES2501_REG_CHWORD1, 0x00 },
464 { AES2501_REG_CHWORD2, 0x6c },
465 { AES2501_REG_CHWORD3, 0x09 },
466 { AES2501_REG_CHWORD4, 0x54 },
467 { AES2501_REG_CHWORD5, 0x78 },
468 { 0xa2, 0x02 },
469 { 0xa7, 0x00 },
470 { 0xb6, 0x26 },
471 { 0xb7, 0x1a },
472 { AES2501_REG_CTRL1, AES2501_CTRL1_REG_UPDATE },
473 { AES2501_REG_IMAGCTRL,
474 AES2501_IMAGCTRL_TST_REG_ENABLE | AES2501_IMAGCTRL_HISTO_DATA_ENABLE |
475 AES2501_IMAGCTRL_IMG_DATA_DISABLE },
476 { AES2501_REG_STRTCOL, 0x10 },
477 { AES2501_REG_ENDCOL, 0x1f },
478 { AES2501_REG_CHANGAIN,
479 AES2501_CHANGAIN_STAGE1_2X | AES2501_CHANGAIN_STAGE2_2X },
480 { AES2501_REG_ADREFHI, 0x70 },
481 { AES2501_REG_ADREFLO, 0x20 },
482 { AES2501_REG_CTRL2, AES2501_CTRL2_SET_ONE_SHOT },
483 { AES2501_REG_LPONT, AES2501_LPONT_MIN_VALUE },
486 static const struct aes2501_regwrite capture_reqs_2[] = {
487 { AES2501_REG_IMAGCTRL,
488 AES2501_IMAGCTRL_TST_REG_ENABLE | AES2501_IMAGCTRL_HISTO_DATA_ENABLE |
489 AES2501_IMAGCTRL_IMG_DATA_DISABLE },
490 { AES2501_REG_STRTCOL, 0x10 },
491 { AES2501_REG_ENDCOL, 0x1f },
492 { AES2501_REG_CHANGAIN, AES2501_CHANGAIN_STAGE1_16X },
493 { AES2501_REG_ADREFHI, 0x70 },
494 { AES2501_REG_ADREFLO, 0x20 },
495 { AES2501_REG_CTRL2, AES2501_CTRL2_SET_ONE_SHOT },
498 static const struct aes2501_regwrite strip_scan_reqs[] = {
499 { AES2501_REG_IMAGCTRL,
500 AES2501_IMAGCTRL_TST_REG_ENABLE | AES2501_IMAGCTRL_HISTO_DATA_ENABLE },
501 { AES2501_REG_STRTCOL, 0x00 },
502 { AES2501_REG_ENDCOL, 0x2f },
503 { AES2501_REG_CHANGAIN, AES2501_CHANGAIN_STAGE1_16X },
504 { AES2501_REG_ADREFHI, 0x5b },
505 { AES2501_REG_ADREFLO, 0x20 },
506 { AES2501_REG_CTRL2, AES2501_CTRL2_SET_ONE_SHOT },
509 static int capture(struct fp_img_dev *dev, gboolean unconditional,
510 struct fp_img **ret)
512 int r;
513 struct fp_img *img;
514 unsigned int nstrips;
515 unsigned char *cooked;
516 unsigned char *imgptr;
517 unsigned char buf[1705];
518 int sum;
519 int i;
521 /* FIXME can do better here in terms of buffer management? */
522 fp_dbg("");
524 r = write_regv(dev, capture_reqs_1, ARRAY_SIZE(capture_reqs_1));
525 if (r < 0)
526 return r;
528 r = read_data(dev, buf, 159);
529 if (r < 0)
530 return r;
532 r = write_regv(dev, capture_reqs_2, ARRAY_SIZE(capture_reqs_2));
533 if (r < 0)
534 return r;
536 r = read_data(dev, buf, 159);
537 if (r < 0)
538 return r;
540 /* FIXME: use histogram data above for gain calibration (0x8e xx) */
542 img = fpi_img_new((3 * MAX_FRAMES * FRAME_SIZE) / 2);
543 imgptr = img->data;
544 cooked = imgptr + (MAX_FRAMES * FRAME_SIZE) / 2;
546 for (nstrips = 0; nstrips < MAX_FRAMES; nstrips++) {
547 int threshold;
549 r = write_regv(dev, strip_scan_reqs, ARRAY_SIZE(strip_scan_reqs));
550 if (r < 0)
551 goto err;
552 r = read_data(dev, buf, 1705);
553 if (r < 0)
554 goto err;
555 memcpy(imgptr, buf + 1, 192*8);
556 imgptr += 192*8;
558 threshold = regval_from_dump((buf + 1 + 192*8 + 1 + 16*2 + 1 + 8),
559 AES2501_REG_DATFMT);
560 if (threshold < 0) {
561 r = threshold;
562 goto err;
565 sum = sum_histogram_values((buf + 1 + 192*8), threshold & 0x0f);
566 if (sum < 0) {
567 r = sum;
568 goto err;
570 fp_dbg("sum=%d", sum);
571 if (sum == 0)
572 break;
574 if (nstrips == MAX_FRAMES)
575 fp_warn("swiping finger too slow?");
577 img->height = assemble(img->data, cooked, nstrips);
578 for (i = 0; i < img->height * FRAME_WIDTH; i++)
579 img->data[i] = (cooked[i] << 4) | 0xf;
581 img = fpi_img_resize(img, img->height * FRAME_WIDTH);
582 img->flags = FP_IMG_V_FLIPPED | FP_IMG_H_FLIPPED | FP_IMG_COLORS_INVERTED;
583 *ret = img;
584 return 0;
585 err:
586 g_free(img);
587 return r;
590 static const struct usb_id id_table[] = {
591 { .vendor = 0x08ff, .product = 0x2580 },
592 { 0, 0, 0, },
595 struct fp_img_driver aes2501_driver = {
596 .driver = {
597 .id = 4,
598 .name = FP_COMPONENT,
599 .full_name = "AuthenTec AES2501",
600 .id_table = id_table,
602 .flags = 0,
603 .img_height = -1,
604 .img_width = 192,
606 /* temporarily lowered until image quality improves */
607 .bz3_threshold = 20,
609 .init = dev_init,
610 .exit = dev_exit,
611 .await_finger_on = await_finger_on,
612 .capture = capture,